La mia collezione sequenziale dovrebbe iniziare dall'indice 0 o dall'indice 1?

25

Sto creando un modello a oggetti per un dispositivo che ha più canali. I nomi usati tra il client e I sono Channel e ChannelSet . ("Set" non è semanticamente preciso, perché è ordinato e non è un set corretto, ma questo è un problema per un tempo diverso.)

Sto usando C #. Ecco un esempio di utilizzo di 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

Tutto è dandy. Tuttavia, i client non sono programmatori e assolutamente saranno confusi dall'indicizzazione zero: il primo canale è il canale 1. Ma, per coerenza con C #, voglio mantenere il ChannelSet indicizzato da zero .

Questo sicuramente causerà alcune disconnessioni tra il mio team di sviluppo ei client quando interagiscono. Ma peggio ancora, qualsiasi incongruenza nel modo in cui questo viene gestito all'interno del codebase è un potenziale problema. Ad esempio, ecco una schermata dell'interfaccia utente in cui l'utente finale ( che pensa in termini di 1 indicizzazione ) sta modificando il canale 13:

Il pulsante Save alla fine produrrà un certo codice. Se ChannelSet è 1 indicizzato:

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

o questo se è indicizzato a zero:

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

Non sono sicuro di come gestirlo. Ritengo che sia una buona pratica mantenere un elenco di cose ordinato, con indice intero (il ChannelSet ) coerente con tutte le altre interfacce di matrice ed elenco nell'universo C # (indicizzando zero ChannelSet ). Ma poi ogni pezzo di codice tra l'interfaccia utente e il back-end avrà bisogno di una traduzione (sottrazione di 1), e sappiamo tutti quanto siano già insidiosi e comuni gli errori di off-by-one.

Quindi, una decisione del genere ti ha mai morso? Dovrei azzerare l'indice o un indice?

    
posta kdbanman 10.07.2015 - 02:49
fonte

8 risposte

24

Sembra che tu stia confondendo l'Identificatore per Channel con la sua posizione all'interno di ChannelSet . Quello che segue è la mia visualizzazione di come il tuo codice / commenti dovrebbe apparire al momento:

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

Sembra che tu abbia deciso che poiché Channel s all'interno di ChannelSet sono identificati da numeri che hanno un limite superiore e inferiore devono essere indici e quindi dato che è C #, Basato su 0 Se il modo naturale di riferirsi a ciascuno dei canali è di un numero compreso tra 1 e X, fare riferimento ad essi con un numero compreso tra 1 e X. Non tentare di forzarli in indici.

Se vuoi davvero fornire un modo per accedervi tramite indice basato su 0 (quale vantaggio offre all'utente finale o agli sviluppatori che consumano il codice?) quindi implementa un indicizzatore :

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];
    }
}
    
risposta data 10.07.2015 - 16:06
fonte
35

Mostra l'interfaccia utente con indice 1, utilizza l'indice 0 nel codice.

Detto questo, ho lavorato con dispositivi audio come questo e ho utilizzato l'indice 1 per i canali e progettato il codice per non utilizzare mai "Indice" o indicizzatori per evitare la frustrazione. Alcuni programmatori si sono lamentati, quindi l'abbiamo cambiato. Poi altri programmatori si sono lamentati.

Scegline uno e attaccalo. Ci sono problemi più grandi da risolvere nel grande progetto di far uscire il software.

    
risposta data 10.07.2015 - 03:16
fonte
21

Usa entrambi.

Non mescolare l'interfaccia utente con il codice principale. Internamente (come una libreria) si dovrebbe codificare "senza sapere" come ogni elemento dell'array sarà chiamato dall'utente finale. Utilizza gli array e le raccolte "naturali" indicizzati 0.

La parte del programma che unisce i dati all'interfaccia utente, la vista, dovrebbe fare attenzione a tradurre correttamente i dati tra il Modello mentale dell'utente e la "Biblioteca" che svolge il lavoro effettivo.

Perché è meglio?

  • Il codice può essere più pulito, senza hack per tradurre l'indicizzazione. Ciò aiuta anche i programmatori a non aspettarsi che seguano e ricordino di usare convenzioni innaturali.
  • Gli utenti useranno l'indicizzazione che si aspettano. Non vuoi annoiarli.
risposta data 10.07.2015 - 03:23
fonte
12

Puoi vedere la collezione da due angolazioni diverse.

(1) È, in primo luogo, una raccolta sequenziale regolare, come una matrice o una lista. L'indice da 0 è ovviamente la soluzione giusta, in seguito alla convenzione. Assegni abbastanza voci e il numero del canale della mappa agli indici, che è banale (sottrarre solo 1 ).

(2) La collezione è essenzialmente un mapping tra identificatori di canale e oggetti di informazione del canale. Succede solo che gli identificatori di canale sono un intervallo sequenziale di interi; domani potrebbe essere qualcosa come [1, 2, 3, 3a, 4, 4.1, 6, 8, 13] . Si utilizza questo insieme ordinato come chiavi di mappatura.

Scegli uno degli approcci, documentalo e rispettalo. Dal punto di vista della flessibilità, andrei con (2), perché la rappresentazione del numero del canale (almeno il nome visualizzato) è relativamente probabile che cambi in futuro.

    
risposta data 10.07.2015 - 04:35
fonte
3

Tutti e il loro cane usano indici a base zero. L'utilizzo di indici basati su uno all'interno dell'applicazione causerà problemi di manutenzione per sempre.

Ora ciò che visualizzi in un'interfaccia utente, dipende interamente da te e dal tuo cliente. Basta mostrare i + 1 come numero di canale, insieme al canale #i, se questo rende il cliente felice.

Se esporti un corso, lo esponi ai programmatori. Le persone che sei confuso da un indice a base zero non sono programmatori, quindi qui c'è una disconnessione.

Sembra che tu ti preoccupi della conversione tra interfaccia utente e codice. Se questo ti preoccupa, crea una classe con la rappresentazione dell'interfaccia utente di un numero di canale. Una chiamata che trasforma il numero 12 nella rappresentazione UI "Canale 13" e una chiamata che trasforma "Canale 13" nel numero 12. Dovresti farlo comunque, nel caso in cui il cliente cambi idea, quindi ci sono solo due righe di codice cambiare. E funziona se il cliente richiede numeri romani o lettere dalla A alla Z.

    
risposta data 10.07.2015 - 11:07
fonte
3

Stai mescolando due concetti: indicizzazione e identità. Non sono la stessa cosa e non dovrebbero essere confusi.

Qual è lo scopo dell'indicizzazione? Accesso casuale rapido. Se la performance non è un problema, e data la tua descrizione non lo è, allora usare una collezione che ha un indice non è necessario e probabilmente accidentale.

Se tu (o il tuo team) viene confuso dall'indice contro l'identità, allora puoi risolvere il problema non avendo un indice. Utilizza un dizionario o una enumerabile e ottieni il canale in base al valore.

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

Il primo è più chiaro, il secondo è più breve - possono o non possono essere tradotti nello stesso IL, ma in entrambi i casi, dato che lo stai usando per un menu a discesa, dovrebbe essere abbastanza veloce.

    
risposta data 10.07.2015 - 17:46
fonte
2

Stai esponendo un'interfaccia attraverso la tua classe ChannelSet che ti aspetti che i tuoi utenti interagiscano. Lo renderei il più naturale possibile da usare. Se prevedi che i tuoi utenti inizieranno a contare da 1 invece di 0, esponi questa classe e il suo utilizzo in base a tale aspettativa.

    
risposta data 10.07.2015 - 02:57
fonte
2

L'indicizzazione basata su 0 era popolare e difeso da persone importanti, perché la dichiarazione mostra la dimensione dell'oggetto.

Con i computer moderni, con i computer che useranno, la dimensione dell'oggetto è importante?

Se il tuo langauge (C #) non supporta un modo pulito di dichiarare il primo e l'ultimo elemento di un array, puoi semplicemente dichiarare un array più grande e usare le costanti dichiarate (o le variabili dinamiche) per identificare l'inizio logico e la fine dell'area attiva dell'array.

Per gli oggetti dell'interfaccia utente, puoi quasi sicuramente permetterti di usare un oggetto dizionario per la tua mappatura, (se hai 10 milioni di oggetti, hai un problema di interfaccia utente) e se il miglior oggetto del dizionario risulta essere una lista con spazio sprecato alle due estremità, non hai perso nulla di importante.

    
risposta data 10.07.2015 - 09:40
fonte

Leggi altre domande sui tag