การรวบรวมลำดับของฉันควรเริ่มต้นที่ดัชนี 0 หรือดัชนี 1 หรือไม่


25

ฉันกำลังสร้างแบบจำลองวัตถุสำหรับอุปกรณ์ที่มีหลายช่องทาง คำนามที่ใช้ระหว่างลูกค้าและฉันและChannel ChannelSet("ชุด" ไม่ถูกต้องทางความหมายเพราะเป็นชุดและชุดที่ไม่ถูกต้อง แต่นั่นเป็นปัญหาสำหรับเวลาที่แตกต่างกัน)

ฉันใช้ C # นี่คือตัวอย่างการใช้งานของChannelSet:

// load a 5-channel ChannelSet
ChannelSet channels = ChannelSetFactory.FromFile("some_5_channel_set.json");

Console.Write(channels.Count);
// -> 5

foreach (Channel channel in channels) {
    Console.Write(channel.Average);
    Console.Write(",  ");
}
// -> 0.3,  0.3,  0.9,  0.1,  0.2

ทั้งหมดคือสำรวย อย่างไรก็ตามลูกค้าไม่ใช่โปรแกรมเมอร์และพวกเขาจะสับสนอย่างแน่นอนโดยไม่มีการทำดัชนี - ช่องแรกคือช่องที่ 1 สำหรับพวกเขา แต่เพื่อประโยชน์ของความสอดคล้องกับ C # ผมต้องการที่จะให้ChannelSetจัดทำดัชนีจากศูนย์

นี่เป็นสาเหตุที่ทำให้เกิดการเชื่อมต่อระหว่างทีม dev ของฉันและลูกค้าเมื่อพวกเขามีปฏิสัมพันธ์ แต่ที่แย่กว่านั้นคือความไม่สอดคล้องกันของวิธีการจัดการภายใน codebase นั้นเป็นปัญหาที่อาจเกิดขึ้นได้ ตัวอย่างเช่นนี่คือหน้าจอ UI ที่ผู้ใช้ปลายทาง ( ผู้ที่คิดว่าเป็นดัชนี 1 รายการ ) กำลังแก้ไขช่องทางที่ 13:

ช่อง 13 หรือ 12

ที่Saveปุ่มในที่สุดก็จะส่งผลให้บางรหัส หากChannelSetมีการจัดทำดัชนี 1 รายการ:

channels.GetChannel(13).SomeProperty = newValue;  // notice: 13

หรือนี่ถ้ามันเป็นศูนย์ดัชนี:

channels.GetChannel(12).SomeProperty = newValue;  // notice: 12

ฉันไม่แน่ใจว่าจะจัดการเรื่องนี้อย่างไร ฉันรู้สึกว่าเป็นวิธีปฏิบัติที่ดีในการเก็บรายการสิ่งที่เรียงลำดับและจัดทำดัชนี ( ChannelSet) ที่สอดคล้องกับอาเรย์และรายการอินเตอร์เฟสอื่น ๆ ทั้งหมดใน C # จักรวาล (โดยการทำดัชนีเป็นศูนย์ChannelSet) แต่แล้วโค้ดทุกส่วนระหว่าง UI และแบ็กเอนด์จะต้องมีการแปล (ลบด้วย 1) และเราทุกคนรู้ว่าข้อผิดพลาดแบบร้ายกาจและเป็นเรื่องธรรมดาอยู่แล้ว

ดังนั้นการตัดสินใจแบบนี้จะกัดคุณหรือไม่? ฉันควรเป็นศูนย์ดัชนีหรือหนึ่งดัชนี?


60
"ดัชนีอาร์เรย์ควรเริ่มต้นที่ 0 หรือ 1 หรือไม่การประนีประนอมของฉันที่ 0.5 ถูกปฏิเสธโดยที่ฉันคิดว่าควรพิจารณาอย่างเหมาะสม" - Stan Kelly-Bootle
ริ้น

2
@gnat มันเป็นสิ่งที่ดีที่ฉันอยู่คนเดียวในสำนักงาน - เสียงหัวเราะดังจ้องมองที่หน้าจอคอมพิวเตอร์มักจะไม่ได้เป็นตัวบ่งชี้ที่ดีในการเพิ่มผลผลิต!
kdbanman

4
จำเป็นต้องระบุตำแหน่งของช่องในชุดหรือไม่ คุณไม่สามารถระบุสิ่งอื่นแทน (เช่นความถี่หากเป็นช่องทีวี)
svick

@svick นั่นเป็นจุดที่ดีมาก ฉันอาจอนุญาตให้เข้าถึงช่องทางโดยตัวระบุที่แตกต่างกันในภายหลัง แต่ศัพท์แสงหลักของลูกค้าดูเหมือนว่าจะเป็นหนึ่งในหมายเลขช่องทำดัชนี
kdbanman

จากการอ่านอย่างรวดเร็วดูเหมือนว่าไม่จำเป็นต้องใช้ดัชนีเป็นเรื่องของประสิทธิภาพดังนั้นคุณสามารถใช้ Map บางชนิดเพื่อเชื่อมโยง ID ช่องสัญญาณและแชนเนลโดยตรงโดยไม่ต้องนึกถึงอาร์เรย์ ฉันคิดว่านี่เป็นสิ่งที่ Rob กำลังทำอยู่และฉันก็เห็นด้วยกับวิธีแก้ปัญหาของเขาหากคุณเลือกที่จะใช้ดัชนี
Matthew อ่าน

คำตอบ:


24

มันให้ความรู้สึกเหมือนคุณกำลังมหันต์ระบุสำหรับตำแหน่งภายในChannel ChannelSetต่อไปนี้เป็นภาพของฉันว่ารหัส / ความคิดเห็นของคุณจะดูในขณะนี้:

public sealed class ChannelSet
{
    private Channel[] channels;
    /// <summary>Retrieves the specified channel</summary>
    /// <param name="channelId">The id of the channel to return</param>
    Channel GetChannel(int channelId)
    {
        return channels[channelId-1];
    }
}

รู้สึกเหมือนคุณได้ตัดสินใจว่าเนื่องจากChannels ภายใน a ChannelSetถูกระบุโดยตัวเลขที่มีขอบเขตบนและล่างจะต้องเป็นดัชนีดังนั้นจึงเป็น C #, 0 หากวิธีที่เป็นธรรมชาติในการอ้างถึงแต่ละแชนเนลคือตัวเลขระหว่าง 1 ถึง X ให้อ้างอิงกับแชนเนลเหล่านั้นด้วยตัวเลขระหว่าง 1 ถึง X อย่าพยายามบังคับให้พวกเขากลายเป็นดัชนี

หากคุณต้องการให้วิธีการเข้าถึงพวกเขาด้วยดัชนีตาม 0 (สิ่งนี้จะให้ประโยชน์แก่ผู้ใช้ของคุณหรือนักพัฒนาที่ใช้รหัสหรือไม่?) จากนั้นใช้ตัวสร้างดัชนี :

public sealed class ChannelSet
{
    private Channel[] channels;
    /// <summary>Retrieves the specified channel</summary>
    /// <param name="channelId">The id of the channel to return</param>
    public Channel GetChannel(int channelId)
    {
        return channels[channelId-1];
    }

    /// <summary>Return the channel at the specified index</summary>
    public Channel this[int index]
    {
        return channels[index];
    }
}

2
นี่เป็นคำตอบที่สมบูรณ์และรัดกุมจริงๆ มันเป็นวิธีที่ฉันได้มาจากคำตอบอื่น ๆ
kdbanman

7
ฉันขอยอมรับคำตอบนี้ แต่กระทู้นี้เต็มไปด้วยคำตอบที่ดีดังนั้นให้อ่านต่อไป
kdbanman

ดีมาก @Rob "ฉันรู้วิธีใช้อินเด็กซ์" - นีโอ
Jason P Sallinger

35

แสดง UI พร้อมดัชนี 1 ใช้ดัชนีดัชนี 0 ในรหัส

ที่กล่าวว่าฉันทำงานกับอุปกรณ์เสียงเช่นนี้และใช้ดัชนี 1 สำหรับช่องสัญญาณและออกแบบรหัสไม่ให้ใช้ "ดัชนี" หรือตัวจัดทำดัชนีเพื่อช่วยหลีกเลี่ยงความยุ่งยาก โปรแกรมเมอร์บางคนยังคงบ่นดังนั้นเราจึงเปลี่ยนมัน โปรแกรมเมอร์คนอื่นบ่น

เพียงแค่เลือกหนึ่งและติดกับมัน มีปัญหาที่ใหญ่กว่าในการแก้ไขในรูปแบบที่ยิ่งใหญ่ของการรับซอฟต์แวร์ออกจากประตู


12
ข้อยกเว้นนี้: หากคุณใช้ภาษาที่ใช้ 1 รหัสของคุณควรสอดคล้องกับรหัสที่เหลือและภาษาของคุณดังนั้นใช้ 0 ใน C #, 1-based ใน VBA (!) หรือ Lua UI ของคุณควรเป็นสิ่งที่มนุษย์คาดหวัง (ซึ่งมักจะเป็นแบบอิง 1 ครั้ง)
user253751

1
@immibis - จุดดีฉันไม่ได้คิดอย่างนั้น
Telastyn

3
สิ่งหนึ่งที่ฉันทำพลาดบางครั้งเกี่ยวกับการเขียนโปรแกรมสมัยโบราณในภาษาเบสิกคือ "OPTION BASE" ...
Brian Knoblauch

1
@ BlueRaja-DannyPflughoeft: ในขณะที่ฉันมักจะคิดว่าOption Baseโง่ แต่ฉันก็ชอบคุณลักษณะบางภาษาที่ให้อาร์เรย์เพื่อระบุขอบเขตล่างโดยพลการ ถ้ามีอาร์เรย์ของข้อมูลตามปีตัวอย่างเช่นเกินกว่าที่จะมีอาร์เรย์มิติข้อมูล[firstYear..lastYear]ได้ดีกว่าต้องเข้าถึงองค์ประกอบ[thisYear-firstYear]เสมอ
supercat

1
@ BlueRaja-DannyPflughoeft One man's bug เป็นคุณสมบัติของคนอื่น ...
Brian Knoblauch

21

ใช้ทั้งสองอย่าง

อย่าผสม UI กับรหัสหลักของคุณ ภายใน (ในฐานะห้องสมุด) คุณควรเขียนโค้ด "โดยไม่ทราบ" ว่าแต่ละองค์ประกอบในอาเรย์จะถูกเรียกโดยผู้ใช้ขั้นสุดท้ายอย่างไร ใช้อาร์เรย์และคอลเลกชันที่เป็นดัชนี 0 "ธรรมชาติ"

ส่วนของโปรแกรมที่รวมข้อมูลกับ UI มุมมองควรระมัดระวังในการแปลข้อมูลอย่างถูกต้องระหว่าง Mental Model ของผู้ใช้และ 'Library' ที่ทำงานจริง

ทำไมสิ่งนี้ถึงดีกว่า

  • รหัสสามารถสะอาดกว่าไม่มีแฮ็กในการแปลการทำดัชนี สิ่งนี้ยังช่วยโปรแกรมเมอร์โดยไม่คาดหวังให้พวกเขาทำตามและอย่าลืมใช้ระเบียบแบบผิดธรรมชาติ
  • ผู้ใช้จะใช้การจัดทำดัชนีที่พวกเขาคาดหวัง คุณไม่ต้องการรบกวนพวกเขา

12

คุณสามารถดูคอลเลคชั่นจากสองมุมที่แตกต่างกัน

(1) ในตอนแรกการรวบรวมตามลำดับปกติเช่นอาร์เรย์หรือรายการ ดัชนีจาก0นั้นเห็นได้ชัดว่าเป็นทางออกที่ถูกต้องหลังจากการประชุม คุณจัดสรรรายการที่เพียงพอและแมปหมายเลขสถานีให้กับดัชนีซึ่งไม่สำคัญ (เพียงลบ1)

(2) คอลเล็กชันของคุณคือการจับคู่ระหว่างตัวระบุช่องสัญญาณและวัตถุข้อมูลช่องสัญญาณ มันเพิ่งเกิดขึ้นที่ตัวระบุช่องทางเป็นช่วงของจำนวนเต็มตามลำดับ พรุ่งนี้อาจเป็นอะไร[1, 2, 3, 3a, 4, 4.1, 6, 8, 13]ก็ได้ คุณใช้ชุดคำสั่งนี้เป็นคีย์การแมป

เลือกหนึ่งในวิธีการเอกสารและติดกับมัน จากมุมมองความยืดหยุ่นฉันจะไปกับ (2) เพราะการเป็นตัวแทนของหมายเลขช่อง (อย่างน้อยชื่อที่แสดง) มีแนวโน้มที่จะเปลี่ยนในอนาคต


ฉันขอขอบคุณส่วนที่ 2 ของคำตอบของคุณ ฉันคิดว่าฉันจะยอมรับสิ่งที่ชอบ เข้าถึงดัชนี ( channels[int]) จะเป็นศูนย์จำนวนเต็มจัดทำดัชนีและ accessors รับGetChannelByFrequency, GetChannelByName, GetChannelByNumberจะมีความยืดหยุ่น
kdbanman

1
วิธีที่สองดีที่สุดแน่นอน ผู้แพร่ภาพในท้องที่ของฉันมี 32 ช่องสัญญาณที่มีLCNตั้งแต่ 1 ถึง 201 ซึ่งจะต้องใช้อาร์เรย์แบบเบาบาง (ว่างเปล่า 84%) มันเป็นแนวคิดที่ชอบจัดเก็บกลุ่มคนในอาเรย์ที่จัดทำดัชนีโดยหมายเลขโทรศัพท์
Kelly Thomas

3
นอกจากนี้การรวบรวมใด ๆ ที่มีขนาดเล็กจนมีการแสดงด้วย UI แบบเลื่อนลงนั้นไม่น่าจะเป็นไปได้อย่างยิ่งที่จะได้รับประโยชน์จากคุณสมบัติเฉพาะของอาเรย์เป็นโครงสร้างข้อมูล ดังนั้นสิ่งที่เรียกว่า "ช่อง 1" โดยผู้ใช้เช่นกันอาจจะเรียกว่า "1" ในรหัสเกินไปและใช้หรือDictionary SortedDictionary
Steve Jessop

1
หลักการของความประหลาดใจที่น้อยที่สุดนั้นบ่งบอกว่าoperator [] (int index)ควรเป็นแบบ 0 แต่operator [] (IOrdered index)ไม่น่าจะเป็นไปได้ (ขอโทษสำหรับไวยากรณ์โดยประมาณ, C # ของฉันเป็นสนิมมาก)
9000

2
@kdbanman: โดยส่วนตัวแล้วฉันจะยืนยันว่าทันทีที่คุณ[]ใช้ภาษามากเกินไปในการค้นหาโอเวอร์โหลดนี้โดยใช้คีย์เองผู้เขียนโปรแกรมจะต้องไม่ถือว่าคีย์เริ่มต้น0และต่อเนื่องกันและควรเตะนิสัยนั้นให้เฉียบแหลม พวกเขาอาจเริ่มต้นจาก0, หรือ1, หรือ1000, หรือสตริง"Channel1", นั่นคือจุดรวมของการใช้ตัวดำเนินการ[]กับคีย์ที่กำหนด OTOH ถ้านี่คือ C และมีคนพูดว่า "ฉันควรปล่อยให้องค์ประกอบ0ในอาร์เรย์ที่ไม่ได้ใช้เพื่อเริ่มต้นจาก1" แล้วฉันจะไม่พูดว่า "เห็นได้ชัดใช่" มันจะเป็นการโทรใกล้ ๆ "ไม่"
Steve Jessop

3

ทุกคนและสุนัขของพวกเขาใช้ดัชนีตามศูนย์ การใช้ดัชนีแบบฐานเดียวภายในแอปพลิเคชันของคุณจะทำให้คุณมีปัญหาในการบำรุงรักษาตลอดไป

ตอนนี้สิ่งที่คุณแสดงในส่วนติดต่อผู้ใช้นั้นขึ้นอยู่กับคุณและลูกค้าของคุณ เพียงแสดง i + 1 เป็นหมายเลขช่องทางพร้อมกับช่อง #i หากนั่นทำให้ลูกค้าของคุณมีความสุข

หากคุณเปิดเผยคลาสจากนั้นแสดงให้โปรแกรมเมอร์ทราบ คนที่คุณสับสนโดยดัชนี zero-based ไม่ใช่โปรแกรมเมอร์ดังนั้นจึงมีการตัดการเชื่อมต่อที่นี่

คุณดูเหมือนจะกังวลเกี่ยวกับการแปลงระหว่าง UI และรหัส หากคุณเป็นกังวลให้สร้างคลาสที่มีส่วนติดต่อผู้ใช้แทนหมายเลขช่อง One call เปลี่ยนหมายเลข 12 เป็น UI แทน "Channel 13" และ One call เปลี่ยน "Channel 13" เป็นหมายเลข 12 คุณควรทำเช่นนั้นในกรณีที่ลูกค้าเปลี่ยนใจดังนั้นจึงมีรหัสเพียงสองบรรทัด เพื่อเปลี่ยนแปลง. และใช้งานได้ถ้าลูกค้าขอเลขโรมันหรือตัวอักษร A ถึง Z


1
ฉันไม่สามารถตรวจสอบคำตอบของคุณได้เนื่องจากสุนัขของฉันจะไม่บอกฉันว่าเขาใช้ดัชนีประเภทใด
armani

3

คุณกำลังผสมสองแนวคิด: การจัดทำดัชนีและเอกลักษณ์ พวกเขาไม่เหมือนกันและไม่ควรสับสน

วัตถุประสงค์ของการจัดทำดัชนีคืออะไร? เข้าถึงแบบสุ่มอย่างรวดเร็ว หากประสิทธิภาพไม่ใช่ปัญหาและให้คำอธิบายของคุณเป็นอย่างนั้นให้ใช้คอลเลกชันที่มีดัชนีนั้นไม่จำเป็นและอาจเกิดขึ้นโดยไม่ตั้งใจ

หากคุณ (หรือทีมของคุณ) กำลังสับสนโดยดัชนีกับข้อมูลประจำตัวคุณสามารถแก้ไขปัญหานั้นได้โดยไม่ต้องมีดัชนี ใช้พจนานุกรมหรือแบบนับได้และรับค่าช่อง

channels.First(c=> c.Number == identity).SomeProperty = newValue;
channels[identity].SomeProperty = newValue;

อย่างแรกคือชัดเจนมากขึ้นที่สองสั้นกว่า - พวกเขาอาจหรืออาจไม่ได้รับการแปลเป็น IL เดียวกัน แต่ทั้งสองวิธีถ้าคุณใช้สิ่งนี้ในการเลื่อนลงมันควรจะเร็วพอ


2

คุณเปิดเผยอินเตอร์เฟสผ่านChannelSetคลาสที่คุณคาดหวังให้ผู้ใช้โต้ตอบ ฉันจะทำให้มันเป็นธรรมชาติสำหรับพวกเขาที่จะใช้มากที่สุด หากคุณคาดว่าผู้ใช้ของคุณจะเริ่มนับจาก 1 แทน 0 ดังนั้นให้เปิดเผยคลาสนี้และการใช้งานโดยคำนึงถึงความคาดหวังนั้น


1
ในนั้นมีปัญหาอยู่! ผู้ใช้ปลายทางของฉันคาดว่าจะเริ่มต้นจาก 1 และผู้ใช้ dev ของฉัน (รวมอยู่ในตัวเอง) คาดว่าจะเริ่มจาก 0
kdbanman

1
ดังนั้นฉันขอแนะนำให้ปรับคลาสของคุณเพื่อให้ตรงกับความต้องการของผู้ใช้ปลายทางของคุณ
เบอร์นาร์ด

2

การจัดทำดัชนีแบบ 0 นั้นเป็นที่นิยมและได้รับการปกป้องโดยบุคคลสำคัญเนื่องจากการประกาศแสดงขนาดของวัตถุ

ด้วยคอมพิวเตอร์ที่ทันสมัยพร้อมด้วยคอมพิวเตอร์ที่ผู้ใช้ของคุณจะใช้งานขนาดของวัตถุมีความสำคัญหรือไม่?

หากแคลชของคุณ (C #) ไม่สนับสนุนวิธีการประกาศองค์ประกอบแรกและสุดท้ายของอาร์เรย์อย่างสะอาดคุณสามารถประกาศอาร์เรย์ที่ใหญ่กว่าและใช้ค่าคงที่ที่ประกาศไว้ (หรือตัวแปรแบบไดนามิก) เพื่อระบุจุดเริ่มต้นและจุดสิ้นสุดของตรรกะ พื้นที่ที่ใช้งานของอาร์เรย์

สำหรับวัตถุ UI คุณสามารถที่จะใช้วัตถุพจนานุกรมสำหรับการทำแผนที่ของคุณ (ถ้าคุณมีวัตถุ 10 ล้านรายการคุณมีปัญหา UI) และถ้าวัตถุพจนานุกรมที่ดีที่สุดกลายเป็นรายการที่มี สิ้นเปลืองพื้นที่ทั้งสองด้านคุณไม่ได้สูญเสียสิ่งใดที่สำคัญ


ที่จริงแล้วดัชนี zero-based และหนึ่งตามนั้นเกี่ยวข้องกับวิธีการสร้างอาร์เรย์ในหน่วยความจำ ดัชนี zero-based ใช้หน่วยความจำภายนอก (ภายนอกอาร์เรย์) เพื่อกำหนดขนาดในขณะที่ดัชนีที่ใช้หนึ่งใช้หน่วยความจำภายใน (ดัชนี 0) เพื่อจดจำขนาดของอาร์เรย์ ( โดยปกติ anyways ) ไม่เป็นที่นิยมสำหรับ "ขนาดของวัตถุ" แต่มักจะเกี่ยวข้องกับวิธีการจัดสรรหน่วยความจำภายในสำหรับอาร์เรย์ ไม่ว่าฉันจะไม่แนะนำการรั่วไหลของไบต์อย่างประมาทที่นี่และมี "เพียงเพราะ" แต่พจนานุกรมมักเป็นแนวคิดที่ดีกว่าอยู่แล้ว
phyrfox

@phyrfox: นามธรรมที่ฉันชอบสำหรับการทำดัชนีแบบ zero-based คือการบอกว่า index นั้นระบุตำแหน่งระหว่างวัตถุ วัตถุแรกอยู่ระหว่างดัชนี 0 และ 1 วัตถุที่สองระหว่าง 1 และ 2 ฯลฯ รับ x <= y <= z, ช่วง [x, y] และ [y, z] จะต่อเนื่องกัน แต่ไม่ทับซ้อนกันหรืออย่างใดอย่างหนึ่งหรือ ทั้งสองอาจว่างเปล่าโดยไม่จำเป็นต้องใช้มุมพิเศษ เมื่อใช้โมเดล "ดัชนีอยู่ระหว่างรายการ" โดยมีการทำดัชนีแบบ zero-based รายการของหกรายการจะมีช่วงตั้งแต่ 0 ถึง 6 ด้วยการจัดทำดัชนีแบบฐานเดียวมันจะนั่งตั้งแต่ 1 ถึง 7 โปรดทราบว่าสิ่งที่เป็นนามธรรมนี้เหมาะกับพอยน์เตอร์ "เกินกว่า"
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.