JavaScriptのアンダースコアを使用して重複オブジェクトを削除する


124

私はこの種の配列を持っています:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

私はそれをフィルターにかけたいです:

var bar = [ { "a" : "1" }, { "b" : "2" }];

_.uniqを使用してみましたが、と{ "a" : "1" }は異なるため、機能しません。アンダースコアuniqにオーバーライドされたequals関数を提供する方法はありますか?


コードも投稿してください
Chetter Hummin 2012年

{ "a" : "2" }存在するようなものはありますか?もしそうならそれはそれをユニークにする属性または値ですか?
Matt

はい、私はキーとしての属性を持って、私は、インデックス誰かが別のトピックで私を示したが、その後、私はいくつかの共通ライブラリを使用して自分のコードをきれいにしたかったん実装
plus-

1
プリーチェンジは答えを受け入れました。
Vadorequest、2014

回答:


232

.uniq / .uniqueはコールバックを受け入れます

var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];

var uniqueList = _.uniq(list, function(item, key, a) { 
    return item.a;
});

// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]

ノート:

  1. 比較に使用されるコールバックの戻り値
  2. 一意として使用される一意の戻り値を持つ最初の比較オブジェクト
  3. underscorejs.orgはコールバックの使用法を示していません
  4. lodash.comは使用法を示しています

別の例: コールバックを使用して車のメーカー、リストから色を抽出する


falseには必要ありません_.uniq()。また、lodash では、オブジェクトの_.uniq(a, 'a');プロパティを取得aするため、このように記述することもできます。
ラリーバトル

「 '_.pluck'コールバックショートハンド」は、isSortedの値を渡す場合にのみ機能します(例:_.uniq(a, false, 'a'))github / bestiejs / lodashにpingを実行したところ、問題は端で修正されたとのことでした。したがって、関数を使用していない場合は、最新のものを使用してください。これはアンダースコアの問題ではないかもしれません。
Shanimal 2013年

2
イテレーターは良い名前のように聞こえません。それは、各オブジェクトのIDを判別するためのハッシュのような関数です
Juan Mendes

lodash docsとの一貫性を高めるためにコールバックを使用するように編集されました:)
Shanimal 2013

1
jsbinの例では、更新が可能です。(1)Makes:_(cars).uniq( 'make')。map( 'make')。valueOf()AND(2)色:_(cars).uniq( 'color')。map( 'color' ).valueOf()。あなたは色を熟してクロージャーを作ることができます。(使用するde lodashをアップグレードする場合はすべて)
Vitor Tyburski 14

38

IDに基づいて重複を削除したい場合は、次のようにすることができます。

var res = [
  {id: 1, content: 'heeey'},
  {id: 2, content: 'woah'}, 
  {id: 1, content:'foo'},
  {id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
  return doc.id;
}),function(grouped){
  return grouped[0];
});

//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]

一意の識別子がの場合、承認された回答は機能しませんDate。しかし、これはします。
gunwin 2017年

17

Shipluの答えの実装。

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

var x = _.uniq( _.collect( foo, function( x ){
    return JSON.stringify( x );
}));

console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]

ところで、どうやって4つの賛成票を獲得しましたか?結果のプロパティを取得するには、各配列値をオブジェクトに戻す必要があります。ような何かJSON.parse(x[0]).axが、それは文字列の配列ですオブジェクトの配列ではありませんので。また、b値を一意に追加し、a / bの順序を逆にすると、関数によってそれらは一意と見なされなくなります。(例 `" {\ "a \":\ "1 \"、\ "b \":2} "!=" {\ "b \":2、\ "a \":\ "1 \"} ")何かが足りないかもしれませんが、結果は少なくとも有用ではありませんか?ここで説明するjsbinあるjsbin.com/utoruz/2/editは
Shanimal

1
あなたは正しいですが、同じキーを持っていますが、順序が異なると実装が壊れます。しかし、キーaを含まないオブジェクトが重複している可能性がある場合に、なぜ各オブジェクトのキーのみをチェックするのかわかりませんa。ただし、a一意のID である場合は意味があります。
ラリーバトル

私が質問に答えていたとき、質問の焦点は上書きすることにあるように私には思えました(a ==(=) b when a = b = {a:1})。私の答えのポイントはイテレータでした。動機を気にせずに答えてみました。(たぶん彼らはショーの車のリストからメーカーのリスト、色を抽出したいと思ったかもしれない。jsbin.com/ evodub / 2 / edit)乾杯!
Shanimal 2013年

また、質問をする人が動機を提供するときに、簡潔な答えを出すのに役立つと思います。これはレースなので、私は最初になり、必要に応じて明確にすることを好みます。楽しいセント・パトリック・デイを過ごしてね。
Shanimal 2013年

これがネストされた配列の比較に関する私の質問に答えたので、まあ私は別の賛成票を示しました。オーバーライドする方法のみを探していたiterator
nevi_me

15

私が属性IDを持っている場合、これはアンダースコアでの優先方法です:

var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]

12

下線の一意の lib を使用すると、次のように機能します。_idに基づいてリストを一意にし、_idの文字列値を返します。

var uniqueEntities = _.uniq(entities, function (item, key, a) {
                                    return item._id.toString();
                                });

10

これは単純な解決策です。これは、深いオブジェクト比較を使用して重複をチェックします(非効率でハックなJSONに変換する必要はありません)。

var newArr = _.filter(oldArr, function (element, index) {
    // tests if the element has a duplicate in the rest of the array
    for(index += 1; index < oldArr.length; index += 1) {
        if (_.isEqual(element, oldArr[index])) {
            return false;
        }
    }
    return true;
});

最後の重複要素が保持されるように、配列内で後に重複がある場合は、すべての要素を除外します。

_.isEqual2つのオブジェクト間で最適化された深い比較を実行する重複使用のテストでは、詳細についてアンダースコアisEqualドキュメントを参照してください。

編集:_.filterよりクリーンなアプローチである使用に更新


事前定義された一意のプロパティに依存していませんか?私はそれが好きです。
Don McCurdy、2014年

1
オブジェクトの配列が小さい場合の優れたソリューションですが、ループ内のループは、uniq idを提供するよりもコストがかかります。
ペンナー


7

イテレータ関数を試す

たとえば、最初の要素を返すことができます

x = [['a',1],['b',2],['a',1]]

_.uniq(x,false,function(i){  

   return i[0]   //'a','b'

})

=> [['a'、1]、['b'、2]]


seconds引数は実際にはオプションですが、実行することもできます_.uniq(x,function(i){ return i[0]; });
jakecraige

3

これが私の解決策です(coffeescript):

_.mixin
  deepUniq: (coll) ->
    result = []
    remove_first_el_duplicates = (coll2) ->

      rest = _.rest(coll2)
      first = _.first(coll2)
      result.push first
      equalsFirst = (el) -> _.isEqual(el,first)

      newColl = _.reject rest, equalsFirst

      unless _.isEmpty newColl
        remove_first_el_duplicates newColl

    remove_first_el_duplicates(coll)
    result

例:

_.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ]) 
//=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]

3

アンダースコア私が使用していた文字列を()iterateeの機能

function isUniq(item) {
    return String(item.user);
}
var myUniqArray = _.uniq(myArray, isUniq);

0

私は、この単純なソリューションを簡単な記述方法で解決したかったのですが、少し計算コストがかかりましたが、変数の定義が最小限の簡単なソリューションではないでしょうか。

function uniq(ArrayObjects){
  var out = []
  ArrayObjects.map(obj => {
    if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.push(obj)
  })
  return out
}

0
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);

これを分解してみましょう。最初に、文字列化された値で配列項目をグループ化しましょう

var grouped = _.groupBy(foo, function (f) { 
    return JSON.stringify(f); 
});

grouped 次のようになります。

{
    '{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
    '{ "b" : "2" }' = [ { "b" : "2" } ]
}

次に、各グループの最初の要素を取得します

var bar = _.map(grouped, function(gr)
    return gr[0]; 
});

bar 次のようになります。 [ { "a" : "1" }, { "b" : "2" } ]

まとめて:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);

3
Stackoverflowへようこそ。あなたが提供したコードに加えて、なぜこれが問題を修正するのか、そしてどのように説明するかを試みてください。
jtate

いい電話。ありがとう。これがどのように機能するかの内訳で更新されました。
Kelly Bigley、

-5

次のように簡略化して実行できます。

_.uniq(foo, 'a')


あなたのソリューションはオブジェクトの配列ではなく、配列に対してのみ機能します
Toucouleur
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.