キー/値ペアのJavascriptのオブジェクトと配列


83

非常に単純なデータ構造があるとします。

(personId, name)

...そして、これらの多くをjavascript変数に格納したいとします。私が見ているように、3つのオプションがあります。

// a single object
var people = {
    1 : 'Joe',
    3 : 'Sam',
    8 : 'Eve'
};

// or, an array of objects
var people = [
    { id: 1, name: 'Joe'},
    { id: 3, name: 'Sam'},
    { id: 8, name: 'Eve'}
];

// or, a combination of the two
var people = {
    1 : { id: 1, name: 'Joe'},
    3 : { id: 3, name: 'Sam'},
    8 : { id: 8, name: 'Eve'}
};

2番目または3番目のオプションは、格納する「値」の部分が複数ある(またはあると予想される)場合(たとえば、年齢などを追加する場合)に明らかに進む方法です。したがって、議論のために、この構造で必要なデータ値がこれ以上なくなると仮定しましょう。どちらを選びますか、そしてその理由は何ですか?


編集:この例は、最も一般的な状況を示しています:非シーケンシャルID。


1
また、2D配列があります:(var people = [[1, 'Joe'],[3, 'Sam'],[8,'Eve']];これはIDによる高速ルックアップを提供しませんが、データを格納するための別のオプションです)
ユーザー

回答:


58

各ソリューションにはユースケースがあります。

最初の解決策は、1対1の関係(単純なマッピングなど)を定義しようとしている場合、特にキーをルックアップキーとして使用する必要がある場合に適していると思います。

2番目のソリューションは、一般的に私にとって最も堅牢であると感じています。高速ルックアップキーが必要ない場合は、おそらくそれを使用します。

  • これは自己記述型であるため、キーがユーザーのIDであることを知るために、ユーザーを使用しているに依存する必要はありません 。
  • 各オブジェクトは自己完結型であるため、データを他の場所に渡すのに適しています。2つのパラメーター(idとname)を渡すだけでなく、人に渡すだけです。
  • これはまれな問題ですが、キー値をキーとして使用するのに有効でない場合があります。たとえば、私はかつて文字列変換(たとえば、 ":"から ">")をマップしたかったのですが、 ":"は有効な変数名ではないため、2番目の方法を使用する必要がありました。
  • 一部の(またはすべての)ユーザーにデータを追加する必要がある場合に備えて、簡単に拡張できます。(申し訳ありませんが、あなたの「議論のために」は知っていますが、これは重要な側面です。)

3つ目は、高速なルックアップ時間と上記のいくつかの利点(データの受け渡し、自己記述型)が必要な場合に適しています。ただし、高速なルックアップ時間が必要ない場合は、はるかに面倒です。また、いずれにしても、オブジェクトのIDが人々のIDと何らかの形で異なる場合、エラーのリスクがあります。


1
そこにあなたの3番目のポイントで。この問題を回避するために、オブジェクトのプロパティに角かっこ表記でアクセスできます。varx = {"ab> c ++": "foo"}; alert(x ['ab> c ++']);
nickf 2009年

あなたはプロパティを持ついくつかの予約語の問題を抱えていると私は信じています。しかし、数字を使用している場合は問題ありません。
derobert 2009年

4
@derobert:そうは思いません。x = {"削除":1、 "for":2、 "関数":3}; -これは有効であり、同じ方法でアクセスできます。
nickf 2009年

7

実際には、4番目のオプションがあります。

var people = ['Joe', 'Sam', 'Eve'];

あなたの価値観はたまたま連続しているからです。(もちろん、1つを加算/減算する必要があります---または最初の要素として未定義を置くだけです)。

個人的には、(1)または(3)を使用します。これは、IDで誰かを検索するのが最も速いためです(最悪の場合、O log n)。(2)でid 3を見つける必要がある場合は、インデックスで検索するか(この場合、私の(4)は問題ありません)、検索する必要があります— O(n)。

明確化:O(log n)は最悪であると私は言います。なぜなら、AFAIKと実装は、ハッシュテーブルの代わりに平衡ツリーを使用することを決定する可能性があるからです。衝突が最小限であると仮定すると、ハッシュテーブルはO(1)になります。

nickfからの編集:OPの例を変更したので、この回答はあまり意味がないかもしれません。お詫び申し上げます。

後編集

わかりました、編集後、オプション(3)を選択します。拡張可能で(新しい属性を簡単に追加できます)、高速ルックアップを備えており、反復することもできます。また、必要に応じて、エントリからIDに戻ることもできます。

オプション(1)は、(a)メモリを節約する必要がある場合に役立ちます。(b)オブジェクトからIDに戻る必要はありません。(c)保存されているデータを拡張することは決してありません(たとえば、人の姓を追加することはできません)

オプション(2)は、(a)順序を維持する必要がある場合に適しています。(b)すべての要素を繰り返す必要があります。(c)IDでソートされていない限り、IDで要素を検索する必要はありません(O(log n)でバイナリ検索を実行できます)。もちろん、ソートを維持する必要がある場合は、料金が発生します。挿入のコスト。


(1)と(3)が(2)よりも速い理由は理解できますが、しばらくの間、どのようにしてO(log(n))を取得したのでしょうか。IDはハッシュテーブルに格納する必要があるため、O(1)にする必要はありませんか?
Nathaniel Reinhart

ハッシュテーブルの代わりに平衡ツリーを使用することを決定する実装を見ることができたので、lognを最悪のものとして与えました。もちろん、ハッシュテーブルはO(1)[衝突が最小限であると仮定]になります。
derobert 2009年

IDは必ずしもそれほど単純ではなく、シーケンシャルIRLになることはめったにないため、IDを指定する必要があります。私はそれが貧弱で曖昧な例だったことを認めます。
nickf 2009年

+1、あなたの答えは受け入れられたものより悪くはありません...しかしあなたの4番目の解決策はすべてのデータを保存しないので、ここに正しい4番目のオプションがあります:var people = []; people[1] = 'Joe'; people[3] = 'Sam'; people[8] = 'Eve';または2次元配列として:(var people = []; people[1] = ['Joe', 'Smith']; people[3] = ['Sam', 'Miller']; people[8] = ['Eve', 'Sweet'];例えば ​​'people [によってアクセスされます3] [1]; 'これは、任意のクラス内の高速内部データストレージに非常にうまく機能します-まあ、クラスでは、Javascriptersが気に入らない「新しいWhateverFunction();」を意味します;-) .. ..
マーカス

...しかし、これはidが整数の場合にのみ機能します。それ以外の場合は、「クラシック」ソリューション2(for(var key in object)アクセスで有名なものと一緒に)が通常の場合(O(n / 2))の方法です。 3それはO(1)を持っているので、あなたは、より高速なアクセスのために本当に大きな配列を持っている...そして最後に聞かせてのは、あなたのIDは整数ですが、また場合にはidがまったく整数でないない場合にのみ、上記の溶液1を忘れた場合:var people = {'Smith':'Joe', 'Miller':'Sam', 'Sweet': 'Eve' };(次のようにオブジェクトにアクセスする必要があるためです:alert(people.Smith);これはあまり良くありません!)。
マーカス

2

データが決して変更されないと仮定すると、最初の(単一オブジェクト)オプションが最適です。

構造が単純であるということは、解析が最も速いことを意味します。このような小さな、めったに(またはまったく)変更されないデータセットの場合、頻繁に実行されることを想像することしかできません。この場合、最小限のオーバーヘッドが行く方法。


2

キーと値のペアを管理するための小さなライブラリを作成しました。

https://github.com/scaraveos/keyval.js#readme

それは使用しています

  • キーを格納するオブジェクト。これにより、削除および値の取得操作を高速化し、
  • 非常に高速な値の反復を可能にするリンクリスト

それが役に立てば幸い :)


jsperfリンクを追加してみませんか?
Janus Troelsen 2013年

そのライブラリは素晴らしい、素晴らしい仕事です。たくさんの時間を節約できました。
クリス・ハフ

1

3番目のオプションは、将来を見据えたアプリケーションに最適です。おそらく、個人レコードにフィールドを追加したい場合があるため、最初のオプションは不適切です。また、格納する人が多数いる可能性が高く、レコードをすばやく検索する必要があります。したがって、(オプション#2で行われるように)単純な配列にレコードをダンプすることもお勧めできません。

3番目のパターンは、任意の文字列をIDとして使用し、複雑なPerson構造を持ち、一定時間内にPersonレコードを取得および設定するオプションを提供します。それは間違いなく行く方法です。

オプション#3に欠けていることの1つは、安定した決定論的順序付けです(これはオプション#2の利点です)。これが必要な場合は、人を順番にリストする必要がある場合に備えて、人IDの順序付けられた配列を別個の構造として保持することをお勧めします。利点は、同じデータセットの異なる順序に対して、そのような配列を複数保持できることです。


0

値として名前しか持たないという制約があるため、最初のオプションを選択します。これは最もクリーンで、オーバーヘッドが最小で、ルックアップが最速です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.