配列から重複を削除する


100

次のようなオブジェクトの配列があります。

var array = [
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
    ...
];

ご覧のとおり、一部の名前は繰り返されています。名前のみの新しい配列を取得したいのですが、名前が重複する場合は、再度追加したくありません。この配列が欲しい:

var newArray = ["Name1", "Name2"];

私はこれをやってみようとしていますmap

var newArray = array.map((a) => {
    return a.name;
});

しかし問題はこれが戻ることです:

newArray = ["Name1", "Name1", "Name2", "Name2"];

mapに何らかの条件を設定して、既存の要素を返さないようにするにはどうすればよいですか?これをmap、他のECMAScript 5またはECMAScript 6の機能で実行したいと考えています。


2
次に、アレイから重複を削除します。
Tushar 2016



id:125を含む行がコンマで終わっていないのはなぜですか?
Peter Mortensen 2016

.indexOf()を使用したすべての回答は、配列が大きい場合、2次時間が複雑になるため、パフォーマンス低下することに注意してください。ES6セットを使用するか、ES5オブジェクトを辞書として使用することをお勧めします
joeytwiddle

回答:


210

ES6ではSet、オブジェクトの名前のみをマッピングした後、一意の値に使用できます。

この提案では、新しい構文...で項目を収集するためにスプレッド構文を使用しています

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      names = [...new Set(array.map(a => a.name))];

console.log(names);


9
私の情報のために..何をし...ますか?
Rajshekar Reddy

9
@RajshekarReddy、それは反復可能なオブジェクトで配列を構築するためのスプレッド構文...です。
Nina Scholz、2016

5
私は「セット」自体に賛成するのではなく、スプレッド演算子の賢い使い方に賛成しています。何か新しいことを学んだり、実用的な例に新しいものを適用したりするのはいつでもいいので、この投稿は賛成に値します。
briosheje 16

33
それは私の個人的な意見ですが、かなり一般的なものです。を使用Array.fromすると、変換の意図がはるかによく伝わり(初心者を理解/検索するのも簡単になります)、スプレッドシンタックスは、スプレッドされた要素が多数ある要素の1つだけに使用する必要があります。多分それを「悪い習慣」と呼ぶのは少し厳しすぎるので、申し訳ありませんが、それが一般的なイディオムにならないようにしたいと思います。
Bergi

3
@KRyanはES6が新しいのですか?2015年6月に確定しました。新しい機能の理解と使用を開始する時が
来ました

64

ES 6ではない(設定されていない)JavaScriptソリューションを探している場合は、配列のreduceメソッドを使用できます。

var array=[
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];
var names = array.reduce(function (a, b) {
  if (a.indexOf(b.name) == -1) {
    a.push(b.name)
  }
  return a;
}, []);

console.log(names);


2
この回答には、中間の配列またはセット、特に名前自体のみを含むものを必要としないという利点もあります。(オブジェクトの配列からオブジェクトの配列に直接行きます。)+1
jpmc26

@Iwrestledabearonce、この2番目のパラメーターは、返されたオブジェクトと同じオブジェクトではありませんか?
カイドウ2016

そうですが、並べ替えやフィルターのように、あるものから別のものに直接行くのではなく、空の配列から再構築されます。
クマを1回レスリングしました。

1
@Dekel —小さいバージョン:)var names = array.reduce(function(a, b) { a.indexOf(b.name) === -1 && a.push(b.name) return a; }, []);
Rayon

3
@Rayonソースコードのサイズにあまり注意を払わないでください。これは多くの自作プログラマにとってよくある落とし穴です。最も重要なのは、プログラムが効率的で読みやすいことです。

16

個人的には、誰もがES 6を使いこなす理由がわかりません。それが私のコードである場合、できるだけ多くのブラウザーをサポートしたいと思います。

var array=[
{id:123, value:"value1", name:"Name1"},
{id:124, value:"value2", name:"Name1"},
{id:125, value:"value3", name:"Name2"},
{id:126, value:"value4", name:"Name2"}
];

   // Create array of unique names
var a = (function(a){
  for (var i = array.length; i--;)
    if (a.indexOf(array[i].name) < 0) a.push(array[i].name);
  return a;
})([]);

console.log(a);


2
indexOf常に-ingするのではなく、オブジェクトをディクショナリとして使用するほうがパフォーマンスが向上しませんか?たとえばadded[name] = true、のif(added[name])代わりにif(a.indexOf(name))
Bojidar Marinov 2016

7
「個人的には、なぜみんながes6ですべてのファンシーを手に入れているのかわかりません」なぜを求愛したりgoto fail、インデックス変数を外側のスコープにリークしたりするのでしょうか。古いブラウザの一部を簡単にポリフィル/変換できます。
Jared Smith

5
もっと読みやすい?これは、アイテムを配列にプッシュする、おかしなforループです。はるかに読みやすいより取得doesntの...
私がクマを一度苦闘しました。

4
正直に言って、あなたが不平を言うために何かを探すのが難しすぎるような気がします。
クマを1回レスリングしました。

2
「私は有名なApple SSLバグについて言及している」-コンテキスト外のランダムなコメントでそれを参照し、人々に認識されることを期待できることはそれほど有名ではない。
Hejazzman 2017年

14

あなたは、単に組み合わせることができmapfilter

var array = [
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];

var unique = array
  .map( item => item.name )
  .filter( ( item, idx, arr ) => arr.indexOf( item ) == idx ) 

console.log(unique)


11

あなたは使用することができますObject.keysを()反復のオブジェクト結果から与えられたオブジェクト自身の列挙可能プロパティ名の配列を取得するためarrayの変数をArray.prototype.reduce()キーがどこにあるか破壊名前は

コード:

const array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}],
      names = Object.keys(array.reduce((a, { name }) => (a[name] = 1, a), {}))

console.log(names)


7

ここに多くの良い答えがあります。私はあなたに別の視点を与えることを期待して、いくつかの多様性で貢献したいと思います。

配列はJavaScriptではオブジェクトタイプであるため、同時にハッシュとして使用できます。この機能を使用することにより、O(n)時間の複雑さを伴う単一の削減操作で実行されるジョブを大幅に簡略化できます。

配列キー以外のいくつかのプロパティを保持する配列に満足できない場合は、個別のハッシュオブジェクトを保持することも検討してください。

var array = [{id:123, value:"value1", name:"Name1"},
             {id:124, value:"value2", name:"Name1"},
             {id:125, value:"value3", name:"Name2"},
             {id:126, value:"value4", name:"Name2"}
            ],
result = array.reduce((p,c) => p[c.name] ? p : (p[c.name] = true, p.push(c.name), p), []);
console.log(result);


このES5ソリューションは優れたパフォーマンスを発揮しますが、配列を2つの目的で使用することは混乱を招き、名前の1つが単なる数値である場合は危険です。p[c.name]別のオブジェクトで処理をo行い、後でそれを破棄することをお勧めします。
joeytwiddle

7

name値だけが必要な場合は、a Setを使用する方法に同意します。

ただしnameプロパティに基づいて一意のオブジェクトの配列を取得する場合は、を使用することをお勧めしますMap。マップを作成する簡単な方法は、配列の[key, value]配列を使用することです。

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      unique = new Map(array.map(obj => [obj.name, obj]));

// To get the unique objects
const uniques = Array.from(unique.values());

// Get the names like you already did:
console.log("Names:", uniques.map(obj => obj.name));

// If you ever need the complete array of unique objects, you got a ref:
console.log(JSON.stringify(uniques));
.as-console-wrapper { min-height: 100%; }

の追加の利点は、ソースオブジェクトとの接続を失うことなく、一意でないものを切り取るMap両方のfilter機能を利用できることです。もちろん、オブジェクトの一意のセットを複数回参照する必要がある場合にのみ必要です。



2

ES6ではこれで十分です。

var array=[
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
];

var set = new Set();

array.forEach((a)=>{
    set.add(a.name);
}); 

console.log(Array.from(set));


11
map副作用がないように、純粋な関数で使用されることになっています。これがための仕事だろうforEachreduce
Vincent van der Weele 2016

1

UnderscoreJSを使用して、

array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}];
get_names =  _.pluck(_.uniq(array, 'name'), 'name')
console.log(get_names)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

`


0

ES5では、オブジェクトをO(n)パフォーマンスの辞書として使用します。

これは、すべてのキーが文字列の場合にのみ機能します。

var array = [
    {id: 123, value: "value1", name: "Name1"},
    {id: 124, value: "value2", name: "Name1"},
    {id: 125, value: "value3", name: "Name2"},
    {id: 126, value: "value4", name: "Name2"}
];

var allNames = array.map(item => item.name);

var map = {};
allNames.forEach(name => {
  map[name] = true;
});
var uniqueNames = Object.keys(map);

console.log(uniqueNames);

必要に応じて、1つの式で同じことを行うことができます。

var uniqueNames = Object.keys(allNames.reduce((m, n) => (m[n] = true, m), {}));

しかし、私は命令型が読みやすいと思います。


わかりやすくするために、ES6の矢印関数を使用しました。あなたが本当にtranspilerなしES5をターゲットにしている場合は、代わりに、完全な形式を使用する必要があります:function (item) { return item.name; }
joeytwiddle

の代わりにObject.keys()この回答filter()、マップにまだ保存されていない名前のみを保持するために使用されます。これは非常にエレガントです。
joeytwiddle


0

最大限の互換性が必要な場合は、このような使用法array#forEach()array#indexOf()メソッド、簡潔な構文:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }]

// initialize an empty array named names
let names = [];

// iterate through every element of `array` & check if it's 'name' key's value already in names array if not ADD it 
array.forEach(function(element) { if (names.indexOf(element.name) === -1) names.push(element.name) });
// or use tilde like this:
//array.forEach(function(element) { if (~names.indexOf(element.name)) names.push(element.name) });

console.log(names);

しかし、互換性がある場合は問題になりません使用するECMAScript 6Setオブジェクト、array#mapおよびArray.from()このようなメソッド:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }];

// iterate through every element from array using map and store it in Set(a Set won't have duplicates) then convert the Set back to Array(using Array.from)
let names = Array.from(new Set(array.map(element => element.name)));

console.log(names);


0

それは私が別の空の配列を使用してそれをした方法です。

var array = [
   {id:123, value:"value1", name:"Name1"},
   {id:124, value:"value2", name:"Name1"},
   {id:125, value:"value3", name:"Name2"},
   {id:126, value:"value4", name:"Name2"}	    
];

var array2 = []		
		
for (i=0; i<array.length;i++){						
   if (array2.indexOf(array[i].name) == -1){				
     array2.push(array[i].name);
    }
}			

console.log(array2)	


-1

ワンライナーをお探しの方へ

const names = array.reduce((acc, {name}) => acc.includes(name) ? acc : [name, ...acc], []);

または配列のプロトタイプのメソッドを使用せずに

const { reduce, includes } = Array;
const names = reduce(array, (acc, {name}) => includes(acc, name) ? acc : [name, ...acc], []);

これを処理するためのいくつかの純粋な関数を書くのに役立つかもしれません

const get_uniq_values = (key, arr) => reduce(arr, (a, o) => includes(a, o[key]) ? a : [o[key], ...a], []);

-1
var __array=[{id:123, value:"value1", name:"Name1"},{id:124, value:"value2", name:"Name1"},{id:125, value:"value3", name:"Name2"},{id:126, value:"value4", name:"Name2"}];

function __checkArray(__obj){
    var flag = true;
    for(let i=0; i < __array.length; i++){
        if(__obj.id == __array.id){
            flag = false;
            break;
        }
    }

    return flag;
}

var __valToPush = {id: 127, value: "value5", name: "Name3"};
if(__checkArray(__valToPush)){
    __array.push(__valToPush)
}

11
こんなに多くのアンダースコアを使う特別な理由はありますか?
Nina Scholz、2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.