web-dev-qa-db-ja.com

複数のプロパティによって一意のアンダースコア/ lodash

重複したオブジェクトの配列があり、一意のリストを取得しようとしています。一意性はオブジェクトのプロパティのサブセットによって定義されます。例えば、

{a:"1",b:"1",c:"2"}

そして、一意性の比較でcを無視したいと思います。

私は次のようなことができます

_.uniq(myArray,function(element) { return element.a + "_" + element+b});

私はできることを望んでいた

_.uniq(myArray,function(element) { return {a:element.a, b:element.b} });

しかし、それは機能しません。私ができるようなことはありますか、または複数のプロパティを比較している場合、オブジェクトの同等の表現を作成する必要がありますか?

26
Jeff Storey

残念ながら、これを行う簡単な方法はないようです。このために独自の関数を書くのではなく、(最初の例のように)等価性を直接比較できるものを返す必要があります。

1つの方法は、必要なプロパティを.join()するだけです:

__.uniqBy(myArray, function(elem) { return [elem.a, elem.b].join(); });
_

あるいは、 __.pick_ または __.omit_ を使用して、不要なものをすべて削除できます。そこから、.join()とともに__.values_を使用することも、単に_JSON.stringify_を使用することもできます。

__.uniqBy(myArray, function(elem) {
    return JSON.stringify(_.pick(elem, ['a', 'b']));
});
_

プロパティの順序に関する限り、オブジェクトは決定論的ではないことに注意してください。したがって、明示的な配列アプローチに固執することをお勧めします。

追伸Lodash <4uniqByuniqに置き換えます

30
voithos

Join()アプローチは今でも最も簡単だと思います。以前のソリューションで懸念が生じたにもかかわらず、正しいセパレーターを選択することは、特定の落とし穴(異なる値セットで同じ結合値を返す)を回避するための鍵だと思います。セパレータは単一の文字である必要はなく、データ自体には自然に発生しないと確信できる任意の文字列を使用できます。私は常にこれを行い、セパレータとして「〜!$〜」を使用するのが好きです。\t\r\nなどの特殊文字を含めることもできます。

含まれているデータが本当に予測不可能な場合、おそらく最大長がわかっているので、結合する前に各要素をその最大長まで単純に埋めることができます。

1
IndyWill

Lodashの uniqWith メソッドを使用します。

_.uniqWith(array, [comparator])

このメソッドは_.uniqは、comparatorの要素を比較するために呼び出されるarrayを受け入れることを除きます。結果値の順序は、配列内で発生する順序によって決まります。コンパレータは、2つの引数で呼び出されます:(arrVal、othVal)

comparatortrueを返す場合、アイテムは重複していると見なされ、最初の出現のみが新しい配列に含まれます。


例:
私はlatitudelongitudeを持つ場所のリストを持っています-そのうちのいくつかは同一です-そして、私はユニークな場所のリストを見たいです

const locations = [
  {
    name: "Office 1",
    latitude: -30,
    longitude: -30
  },
  {
    name: "Office 2",
    latitude: -30,
    longitude: 10
  },
  {
    name: "Office 3",
    latitude: -30,
    longitude: 10
  }
];

const uniqueLocations = _.uniqWith(
  locations,
  (locationA, locationB) =>
    locationA.latitude === locationB.latitude &&
    locationA.longitude === locationB.longitude
);

// Result has Office 1 and Office 2
1
Reed Dunkle

@voithosと@Danailを組み合わせた回答にはヒントがあります。これを解決する方法は、配列内のオブジェクトに一意のキーを追加することでした。

サンプルデータの開始

const animalArray = [
  { a: 4, b: 'cat', d: 'generic' },
  { a: 5, b: 'cat', d: 'generic' },
  { a: 4, b: 'dog', d: 'generic' },
  { a: 4, b: 'cat', d: 'generic' },
];

上記の例では、配列をabで一意にする必要がありますが、現在はa: 4b: 'cat'を持つ2つのオブジェクトがあります。 a + bを文字列に結合することにより、確認する一意のキーを取得できます。

{ a: 4, b: 'cat', d: 'generic', id: `${a}-${b}` }. // id is now '4-cat'

注:同じオブジェクト内のオブジェクトのプロパティを参照できないため、オブジェクトの作成中にデータをマップするか、これを行う必要があることは明らかです。

今、比較は簡単です...

_.uniqBy(animalArray, 'id');

結果の配列の長さは3になり、最後の重複が削除されます。

0
Trevor