web-dev-qa-db-ja.com

順次収集は、インデックス0またはインデックス1から開始する必要がありますか?

複数のチャネルを持つデバイスのオブジェクトモデルを作成しています。クライアントと私の間で使用される名詞は、ChannelChannelSetです。 (「セット」は順序付けされており、適切なセットはそうではないため、意味的に正確ではありません。しかし、それは別の時間の問題です。)

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のインデックスをゼロから維持したい

これにより、開発チームとクライアントがやり取りする際に、クライアントとの間にいくつかの接続が切断されることになります。しかしさらに悪いことに、コードベース内でこれがどのように処理されるかについての不整合は潜在的な問題です。たとえば、次のUI画面は、エンドユーザー(が1つのインデックス作成について考える)がチャネル13を編集しているところです。

Channel 13 or 12?

そのSaveボタンは、最終的にいくつかのコードになります。 ChannelSetが1インデックス化されている場合:

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

orインデックスがゼロの場合:

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

私はこれをどのように処理するか本当にわかりません。整数でインデックス付けされたもののリスト(ChannelSet)をC#ユニバースの他のすべての配列およびリストインターフェースと整合させる(ゼロインデックスChannelSetを使用する)ことをお勧めします。 )。しかし、UIとバックエンドの間のすべてのコードには変換(1を引く)が必要であり、私たちは皆、いかに油断のならない一般的なオフバイワンエラーがすでにあるかを知っています。

それで、このような決定はあなたを噛んだことがありますか?インデックスをゼロにするか、1つのインデックスにするか?

25
kdbanman

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

decidedしたように感じます。なぜなら、ChannelChannelSetsは、下限はインデックスである必要があるため、C#の場合は0ベースです。各チャネルを参照する自然な方法が1からXまでの数字である場合は、1からXまでの数字で参照してください。無理にインデックスにしないでください。

0ベースのインデックスでそれらにアクセスする方法を提供したい場合(これにより、エンドユーザー、またはコードを使用する開発者にどのようなメリットがありますか?) Indexer を実装します。

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

Iをインデックス1で表示し、コードでインデックス0を使用します。

そうは言っても、私はこのようなオーディオデバイスで作業し、チャネルにインデックス1を使用し、フラストレーションを回避するために「インデックス」またはインデクサーを使用しないようにコードを設計しました。一部のプログラマーはまだ不満を言っていたので、変更しました。その後、他のプログラマーは不満を述べました。

ただ1つを選んで、それに固執してください。ソフトウェアをドアから出すという壮大な計画では、解決すべきより大きな問題があります。

35
Telastyn

両方を使う。

UIをコアコードと混在させないでください。内部的には(ライブラリとして)、配列の各要素が最終ユーザーによってどのように呼び出されるかを「知らずに」コーディングする必要があります。 「自然な」0インデックスの配列とコレクションを使用します。

データをUIと結合するプログラムの一部であるビューは、ユーザーのメンタルモデルと実際の作業を行う「ライブラリ」の間でデータを正しく変換するように注意する必要があります。

なぜこれが良いのですか?

  • コードはよりクリーンで、インデックスを変換するためのハックはありません。これはまた、プログラマーが不自然な規則に従うことや覚えておくことを期待しないことにより、プログラマーを支援します。
  • ユーザーは期待するインデックスを使用します。あなたはそれらを困らせたくありません。
21
Dietr1ch

コレクションは2つの異なる角度から見ることができます。

(1)そもそも、配列やリストのような通常の順次コレクションです。 0のインデックスは、慣例に従って、明らかに正しいソリューションです。十分なエントリを割り当て、チャネル番号をインデックスにマップします。これは簡単です(1を引くだけ)。

(2)あなたのコレクションは本質的に、チャネル識別子とチャネル情報オブジェクトの間のmappingです。たまたま、チャネル識別子が整数の連続した範囲であることが起こります。明日は[1, 2, 3, 3a, 4, 4.1, 6, 8, 13]のようになるかもしれません。この順序付きセットをマッピングキーとして使用します。

アプローチの1つを選択し、それを文書化して、それに従ってください。柔軟性の観点からは、チャネル番号(少なくとも表示名)の表現が将来比較的変更される可能性が高いため、(2)を使用します。

12
9000

皆とその犬はゼロベースのインデックスを使用します。アプリケーション内で1ベースのインデックスを使用すると、メンテナンスの問題が永遠に発生します。

ユーザーインターフェースに何を表示するかは、完全にあなたとあなたのクライアント次第です。クライアントを満足させる場合は、チャネル番号としてi + 1をチャネル#iと一緒に表示します。

クラスを公開する場合は、それをプログラマーに公開します。ゼロベースのインデックスで混乱している人はプログラマーではないので、ここでは分断があります。

UIとコード間の変換について心配しているようです。それが心配な場合は、チャネル番号のユーザーインターフェイス表現を運ぶクラスを作成します。番号12をUI表現「チャネル13」に変える1回の呼び出しと、「チャネル13」を番号12にする1回の呼び出し。変更する。また、お客様がローマ数字、またはAからZの文字を要求した場合にも機能します。

3
gnasher729

あなたは2つの概念を混同しています:インデックスとアイデンティティです。それらは同じものではなく、混同しないでください。

索引付けの目的は何ですか?高速ランダムアクセス。パフォーマンスに問題がなく、説明に問題がない場合、インデックスを持つコレクションを使用する必要はなく、おそらく偶発的です。

あなた(またはあなたのチーム)がインデックスとIDで混乱している場合は、インデックスを作成しないことで問題を解決できます。辞書または列挙型のいずれかを使用して、値でチャネルを取得します。

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

1つ目はより明確で、2つ目はより短くなっています。同じILに変換される場合と変換されない場合がありますが、どちらの方法でも、これをドロップダウンに使用すると、十分に高速になります。

3
jmoreno

ユーザーが操作することを期待するChannelSetクラスを介してインターフェイスを公開しています。できるだけ自然に使ってもらいたいです。ユーザーが0ではなく1からカウントを開始することが予想される場合は、この予想を念頭に置いて、このクラスとその使用法を公開してください。

2
Bernard

宣言はオブジェクトのサイズを示すため、0ベースのインデックス付けは人気があり、重要な人々から守られました。

最近のコンピューターで、ユーザーが使用するコンピューターで、オブジェクトのサイズはまったく重要ですか?

言語(C#)が配列の最初と最後の要素を宣言するクリーンな方法をサポートしていない場合は、より大きな配列を宣言し、宣言された定数(または動的変数)を使用して、論理的な開始と終了を識別できます。アレイのアクティブ領域。

UIオブジェクトの場合、マッピングにディクショナリオブジェクトを使用する余裕がほぼ確実にあり(1000万のオブジェクトがある場合、UIの問題があります)、最良のディクショナリオブジェクトがどちらかの端でスペースを無駄にし、あなたは重要な何かを失っていません。

2
david