12

次のユースケースでは、独自の並べ替えアルゴリズムを作成しないようにしています。

avatars = {};
avatars[102] = {userInfo: {buddy_name: 'Avatar102', is_online: 1}};
avatars[100] = {userInfo: {buddy_name: 'Avatar100', is_online: 1}};
avatars[101] = {userInfo: {buddy_name: 'Avatar101', is_online: 1}};

console.log(_.keys(avatars));
avatars = _.sortBy(avatars, function(avatar) {return avatar.userInfo.buddy_name.toLowerCase();});
console.log(_.keys(avatars));

コンソール出力は次のとおりです。

  • ["102"、 "100"、 "101"]
  • ["0"、 "1"、 "2"]

ご覧のとおり、undescoreのsortByを使用すると、キーデータが失われます。この構造体は非常に大きくなる可能性があるため、配列に変換してからコレクションに戻すなどのことは避けようとしています。自分のソート関数をロールせずにこれを行う方法はありますか?

4

1 に答える 1

26

あなたavatarsは配列ではなく、単なるオブジェクトです:

avatars = {};

したがって、その要素の順序は定義されていません

プロパティを列挙するメカニズムと順序(最初のアルゴリズムのステップ6.a、2番目のアルゴリズムのステップ7.a)は指定されていません。

および15.2.3.7(および15.2.3.14):

実装がfor-inステートメントの列挙の特定の順序を定義する場合、このアルゴリズムのステップ3でリスト要素を順序付けるために、同じ列挙順序を使用する必要があります。

セクション8.6をチェックして、オブジェクト内のプロパティの順序についての言及があるかどうかを確認することもできます。オブジェクトプロパティの順序付けの唯一の要件は、実装がどこでも順序を定義する場合、どこでも同じ順序を使用する必要があるということですが、それは大きな場合です。ほとんどの実装はおそらくオブジェクトのキーの挿入順序を使用しますが、それらを必要とするものは見つかりません(オブジェクトのキーの特定の順序を定義する仕様で誰かが何かを指摘できる場合はコメントをいただければ幸いです)。

とは言うものの、アンダースコアsortByは基本的にシュワルツ変換sortであり、標準のJavaScriptとアンダースコアを組み合わせてpluckシュワルツ変換のメモラッパーをアンラップします。pluck配列を返すので、配列sortByも返します。したがって、最後の_.keys(avatars)呼び出しは実際_.keysには配列を呼び出しています。配列のキー(別名列挙可能なプロパティ)は配列のインデックスであり、それらはゼロから始まる連続した整数です。

間違ったデータ構造を使用しています。スパース配列が必要であるが、配列のように操作する(つまり、並べ替える)必要がある場合は、オブジェクト内にインデックスを配置し、次pluckの代わりに通常の配列を使用する必要がありkeysます。

var avatars = [
    {idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}},
    {idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}},
    {idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}}
];
console.log(_(avatars).pluck('idx'));
avatars = _(avatars).sortBy(function(avatar) {
    return avatar.userInfo.buddy_name.toLowerCase();
});
console.log(_(avatars).pluck('idx'));

デモ: http: //jsfiddle.net/ambiguous/UCWL2/

それまでに迅速なアクセスも必要な場合は、直接アクセスidx用の並列オブジェクトを設定できます。idx

var avatars_by_idx = { };
for(var i = 0; i < avatars.length; ++i)
    avatars_by_idx[avatars[i].idx] = avatars[i];

次にavatars_by_idx、探している直接アクセスを提供します。もちろん、同期を維持する必要がありますがavatarsavatars_by_idx両方をオブジェクトの背後に隠せば、それほど難しくはありません。

于 2012-05-16T18:33:54.337 に答える