Sıralı koleksiyonum dizin 0 mı yoksa dizin 1'den mi başlamalı?


25

Birden fazla kanalı olan bir cihaz için bir nesne modeli oluşturuyorum. Müşteri ile ben arasında kullanılan isimler Channelve ChannelSet. ("Set" anlamsal olarak doğru değildir, çünkü sıralanmıştır ve uygun bir set değildir. Ama bu farklı bir zaman için bir problemdir.)

C # kullanıyorum İşte bir kullanım örneği 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

Hepsi züppe. Bununla birlikte, istemciler programcı değildir ve kesinlikle sıfır indeksleme ile karıştırılırlar - ilk kanal onlara kanal 1'dir. Ancak, C # ile tutarlılık uğruna, ChannelSetendekslenmiş sıfırdan tutmak istiyorum .

Bunun, dev ekibim ile müşteriler arasında etkileşim kurduğunda bazı bağlantıların kesilmesine neden olacağından emin olabilirsiniz. Daha da kötüsü, bunun kod temeli içerisinde nasıl ele alındığına dair herhangi bir tutarsızlık potansiyel bir problemdir. Örneğin, burada (1 indeksleme açısından düşünen son kullanıcının ) kanal 13'ü düzenlediği bir UI ekranı :

Kanal 13 veya 12?

Bu Savedüğme sonunda bir kodla sonuçlanacak. Eğer ChannelSet1 endeksli:

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

ya da eğer sıfır indekslenmişse:

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

Bununla nasıl başa çıkacağımdan emin değilim. Sıralı, tamsayı indeksli bir şeylerin listesini (the ChannelSet) tüm diğer dizi ile tutarlı tutmak ve C # evrendeki arayüzleri listelemek için iyi bir uygulama gibi hissediyorum (sıfır indeksleme ile ChannelSet). Fakat kullanıcı arayüzü ile arka uç arasındaki her kod parçası bir çeviriye ihtiyaç duyacak (1 ile çıkartma) ve hepimiz ne kadar sinsi ve yaygın bir hatalar olduğunu biliyoruz.

Peki, böyle bir kararın seni hiç ısırması oldu mu? Sıfırlama endeksi mi yoksa bir endeks mi yapmalıyım?


60
"Dizin endeksleri 0 mı yoksa 1'de mi başlamalı? 0,5 ​​ödün vermem, uygun bir düşünce olmadan reddedildi." - Stan Kelly-Bootle
gnat

2
@gnat Ofiste yalnız kalmam iyi bir şey - bilgisayar ekranına bakan kahkaha patlamaları genellikle verimlilik göstergeleri değildir!
kdbanman

4
Kanalların setteki konumlarıyla tanımlanması gerekiyor mu? Onları bunun yerine başka bir şeyle tanımlayamıyor musunuz (örneğin, televizyon kanalları olsaydı frekans)
svick,

@svick, bu harika bir nokta. Daha sonra farklı tanımlayıcılar tarafından kanal erişimine izin verebilirim, ancak müşterilerin ana dili gerçekten endeksli bir kanal numarası gibi görünüyor.
kdbanman

Kısa bir okumadan, indeksleri verimlilik meselesi olarak kullanmaya gerek yok gibi gözüküyor, bu nedenle dizileri düşünmeye gerek kalmadan doğrudan kanal kimliklerini ve kanalları bağlamak için bir tür Harita kullanabilirsiniz. Bence Rob'ın elde ettiği şey bu ve endeksleri kullanmayı tercih ederseniz çözümü ile de aynı fikirdeyim.
Matthew

Yanıtlar:


24

İçin tanımlayıcısını Channela içindeki konumu ile karıştırıyormuş gibi hissediyorum ChannelSet. Aşağıdaki, kodunuzun / yorumlarınızın şu anda nasıl görüneceğine dair görselleştirmem:

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];
    }
}

Eğer gibiyim his yapar karar çünkü Channelbir dahilinde ler ChannelSetbir üst sahip numaralarıyla tespit edilir ve bağlı düşük değerler onlar indeksleri olmalı ve bu nedenle 's C # gibi 0 tabanlı. Kanalların her birine atıfta bulunmanın doğal yolu 1 ile X arasında bir sayıysa, onları 1 ile X arasında bir sayı ile belirtin. Bunları dizin oluşturmaya zorlamayın.

Onlara gerçekten 0 temelli indeksle erişmenin bir yolunu bulmak istiyorsanız (bu, son kullanıcınıza veya kodu kullanan geliştiricilere ne yararı sağlar?), Bir İndeksleyici uygulayın :

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
Bu gerçekten eksiksiz ve özlü bir cevaptır. Diğer cevaplardan türetdiğim yaklaşım tam olarak bu.
kdbanman

7
Yoldan geçenler, Bu cevabı kabul ettim, fakat bu konu iyi cevaplarla dolu, bu yüzden okumaya devam et.
kdbanman

Çok güzel, @Rob. "Dizinleyicileri nasıl kullanacağımı biliyorum." - Neo
Jason P Sallinger

35

Dizin 1 ile kullanıcı arayüzünü gösterin, kod içinde dizin 0 kullanın.

Bununla birlikte, bunun gibi ses cihazlarıyla çalıştım ve kanallar için index 1'i kullandım ve kodu asla "Index" veya indeksleyicileri, sıkıntıdan kaçınmaya yardımcı olmak için kullanmayacak şekilde tasarladım. Bazı programcılar hala şikayet etti, biz de değiştirdik. Sonra diğer programcılar şikayet etti.

Sadece bir tane seç ve buna sadık kal. Yazılımın kapı dışına alınmasının büyük şemasında çözülmesi gereken daha büyük problemler var.


12
Bunun istisnası: 1 tabanlı bir dil kullanıyorsanız. Kodunuz, kodunuzun geri kalanıyla ve dilinizle tutarlı olmalıdır, bu nedenle 0, CBA, 1, VBA (!) Veya Lua’ya dayalı. Kullanıcı arabiriminiz, insanların beklediği her ne olmalıdır (ki neredeyse her zaman 1 tabanlı).
user253751

1
@ immibis - iyi nokta, bunu düşünmemiştim.
Telastyn

3
BASIC'te eski günlerde programlama hakkında zaman zaman özlediğim bir şey "OPTION BASE" ...
Brian Knoblauch

1
@ BlueRaja-DannyPflughoeft: Her zaman Option Basesaçma sapan olsa da, bazı dillerin dizilerin ayrı ayrı rasgele daha düşük sınırlar belirleyebilmelerini sağlayan bazı dilleri sevdim. Örneğin, yıllara göre bir veri dizisi varsa, örneğin, boyutlandırılmış bir diziye [firstYear..lastYear]sahip olmanın ötesinde, her zaman öğeye erişmekten daha güzel olabilir [thisYear-firstYear].
supercat

1
@ BlueRaja-DannyPflughoeft Bir erkeğin böceği başka bir erkeğin özelliği ...
Brian Knoblauch

21

İkisini de kullan.

Kullanıcı arabirimini çekirdek kodunuzla karıştırmayın. Dahili olarak (bir kütüphane olarak) dizideki her elemanın son kullanıcı tarafından nasıl çağrılacağını "bilmeden" kodlamalısınız. "Doğal" 0 dizinli dizileri ve koleksiyonları kullanın.

Programın UI ile veriyi birleştiren kısmı, görünüm, kullanıcının Zihinsel Modeli ile asıl işi yapan 'Kütüphane' arasında doğru bir şekilde çeviri yapmaya özen göstermelidir.

Bu neden daha iyi?

  • Kod daha temiz olabilir, dizin oluşturmayı kesmek için kesmek gerekmez. Bu aynı zamanda programcıların takip etmelerini beklemeyerek ve doğal olmayan sözleşmeleri kullanmayı hatırlamalarını sağlayarak yardımcı olur.
  • Kullanıcılar bekledikleri endekslemeyi kullanacaklar. Onları kızdırmak istemezsin.

12

Koleksiyonu iki farklı açıdan görebilirsiniz.

(1) İlk olarak, bir dizi veya liste gibi düzenli bir sıralı koleksiyondur . 0Bu konvansiyonu takip eden endeks açıkça o zaman doğru çözümdür. Yeterli sayıda giriş tahsis eder ve kanal numarasını önemsiz olan indekslere eşlersiniz (sadece çıkartın 1).

(2) Koleksiyonunuz, esas olarak kanal tanımlayıcıları ve kanal bilgi nesneleri arasında bir haritalamadır . Bu sadece kanal tanımlayıcıların sıralı bir tamsayı aralığı olduğu anlamına gelir; yarın gibi bir şey olabilir [1, 2, 3, 3a, 4, 4.1, 6, 8, 13]. Bu sıralı seti eşleme anahtarı olarak kullanıyorsunuz.

Yaklaşımlardan birini seçin, belgelendirin ve buna bağlı kalın. Esneklik açısından bakıldığında, (2) ile giderdim, çünkü kanal numarasının (en azından görüntülenen adın) gösterilmesinin gelecekte değişmesi muhtemeldir.


Cevabınızın 2. bölümünü gerçekten takdir ediyorum. Sanırım onun gibi bir şey benimseyeceğim. İndeks erişimci ( channels[int]) olacaktır sıfır endeksli tamsayılar ve alın erişimcileri GetChannelByFrequency, GetChannelByName, GetChannelByNumberesnek olacaktır.
kdbanman

1
İkinci yaklaşım kesinlikle en iyisidir. Yerel yayıncılarım , 1 ile 201 arasında değişen LCN'lere sahip 32 kanal sunuyor. Bu, seyrek bir dizi (% 84 boş) gerektiriyor. Kavramsal olarak, bir grup insanı telefon numarasına göre dizilmiş bir dizide depolamak gibidir.
Kelly Thomas

3
Ayrıca, bir UI açılır listesiyle temsil edilen çok küçük herhangi bir koleksiyonun , bir dizinin veri yapısı olarak belirli performans özelliklerinden faydalanması son derece düşüktür. Bu nedenle, kullanıcı tarafından "kanal 1" olarak adlandırılan şey, kodda da "1" olarak adlandırılabilir ve a Dictionaryveya kullanın SortedDictionary.
Steve Jessop

1
En küçük sürpriz ilkesi, operator [] (int index)0 temelli olması gerektiği, ancak öyle olmaması gerektiği anlamına gelir operator [] (IOrdered index). (Yaklaşık sözdizimi için özür dilerim, benim C # çok paslı.)
9000 15

2
@kdbanman: şahsen, []keyfi bir anahtarla arama yapmak için bu aşırı yükü kullanan bir dilde aşırı yüklenir yüklenmez, programcılar anahtarların başladığını 0ve bitişik olduğunu varsaymamalı ve bu alışkanlığı keskin bir şekilde tekmelemeliler. Operatörün keyfi tuşlarla kullanılmasının asıl amacı bu olabilir 0, ya 1da 1000ya da dize . OTOH, eğer bu C ise ve birileri "eğer başlamak için kullanılmamış bir dizide elementi bırakmalı mıyım " demeliydi "sonra" açıkçası evet "demezdim, yakın bir çağrı olurdu, ama yalın olurdu "yok hayır". "Channel1"[]01
Steve Jessop,

3

Herkes ve köpeği sıfır tabanlı dizinler kullanıyor. Uygulamanızın içinde tek tabanlı dizinler kullanmak, sonsuza dek bakım sorunlarına neden olur.

Şimdi bir kullanıcı arayüzünde ne gösterdiğiniz, tamamen size ve müşterinize bağlı. İstemcinizi mutlu edecekse, i + 1'i kanal numarası olarak, #i kanalıyla birlikte görüntülemeniz yeterlidir.

Bir sınıfa maruz kalırsanız, programlayıcılara maruz bırakırsınız. Sıfır tabanlı bir dizin tarafından karıştırıldığınız insanlar programcı değildir, bu nedenle burada bağlantı kopar.

UI ve kod arasındaki dönüşüm konusunda endişeleniyor gibisiniz. Bu sizi endişelendiriyorsa, bir kanal numarasının kullanıcı arayüzü temsilini taşıyan bir sınıf oluşturun. Bir numarayı 12 numarayı UI temsili olan "Kanal 13" e, bir tane de "Kanal 13" u 12 numaraya çeviren bir çağrı, müşterinin fikrini değiştirmesi durumunda, yine de yapmalısınız. değişmek. Ve müşteri romen rakamları veya A'dan Z'ye harfleri isterse çalışır.


1
Cevabınızı doğrulayamıyorum çünkü köpeğim bana ne tür indeksler kullandığını söylemiyor.
armani,

3

İki kavramı karıştırıyorsunuz: indeksleme ve kimlik. Onlar aynı şey değil ve karıştırılmamalıdır.

İndekslemenin amacı nedir? Hızlı rastgele erişim. Performans bir sorun değilse ve açıklamanız verilmemişse, dizini olan bir koleksiyonu kullanmak gereksiz ve muhtemelen kazaradır.

Siz (veya ekibiniz) indeks ile kimliğe göre karıştırılıyorsa, o zaman bir indeks sahibi olmadan bu sorunu çözebilirsiniz. Bir sözlük veya numaralandırılabilir kullanın ve kanalı değerine göre alın.

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

Birincisi daha açık, ikincisi daha kısa - aynı IL'ye çevrilmiş olabilirler veya olmayabilirler, ancak bunu bir düşüş için kullandığınız takdirde her iki şekilde de yeterince hızlı olmalıdır.


2

ChannelSetKullanıcılarınızın birbirleriyle etkileşimde bulunmasını beklediğiniz bir sınıfla sınıfınızdakileri ortaya çıkarıyorsunuz . Onları mümkün olduğunca kullanmalarını doğal hale getirirdim. Kullanıcılarınızın 0 yerine 1'den saymaya başlamasını beklerseniz, o zaman bu sınıfı ve kullanımını bu beklenti dikkate alarak gösterin.


1
Sorun burada yatıyor! Son kullanıcılarımın 1'den başlaması bekleniyor ve dev kullanıcılarım (kendim dahil) 0'dan başlaması bekleniyor
kdbanman

1
Bu yüzden sınıfınızı, son kullanıcılarınızın ihtiyaçlarını karşılayacak şekilde uyarlamanızı öneririm.
Bernard,

2

0 tabanlı indeksleme popülerdi ve önemli kişilerce savundu, çünkü bildiri nesnenin boyutunu gösteriyor.

Modern bilgisayarlarda, kullanıcılarınızın kullanacağı bilgisayarlarla, nesnenin boyutu hiç önemli mi?

Eğer diliniz (C #) dizinin ilk ve son elemanını bildirmenin temiz bir yolunu desteklemiyorsa, daha büyük bir dizi tanımlayabilir ve mantıksal başlangıcını ve sonunu tanımlamak için belirtilen sabitleri (veya dinamik değişkeni) kullanabilirsiniz. dizinin aktif alanı.

UI nesneleri için, eşlemeniz için neredeyse bir sözlük nesnesini kullanmayı göze alabilirsiniz (10 milyon nesneniz varsa, bir UI sorununuz varsa) ve en iyi sözlük nesnesi bir liste haline gelirse Her iki uçta boşa harcanan, önemli bir şey kaybetmediniz.


Aslında sıfır tabanlı ve tek tabanlı dizinlerin, dizinin bellekte nasıl oluşturulduğuyla ilgisi var. Sıfır tabanlı dizinler, boyutu belirlemek için harici belleği (dizinin dışında), bir tabanlı dizinler dizinin boyutunu ( genellikle de olsa) hatırlamak için dahili belleği (dizin 0) kullanır . “Nesnenin boyutu” için popüler değildir, ancak genellikle belleğin diziler için dahili olarak nasıl tahsis edildiğiyle ilgilidir. Ne olursa olsun, dikkatlice sızan baytlar burada ve orada "sadece çünkü" tavsiye etmem. Ancak, sözlükler genellikle zaten daha iyi bir fikirdir.
phyrfox

@phyrfox: Sıfır tabanlı indeksleme için tercih ettiğim soyutlama, indekslerin nesneler arasındaki pozisyonları tanımladığını söylemek ; ilk nesne 0 ile 1 arasındadır, ikincisi 1 ile 2 arasında vs. her ikisi de özel köşe kılıfı gerektirmeden boş olabilir. Sıfır temelli dizine sahip "endeksler öğeler arasında oturuyor" modelini kabul ederken, altı maddeden oluşan bir liste 0 ila 6 arasındadır; bir temelli indeksleme ile 1 ila 7 arasında olacaktır. Bu soyutlamanın "bir ötesinde" işaretçilere iyi uyduğunu unutmayın.
supercat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.