web-dev-qa-db-ja.com

JS配列から重複した値を削除

私は重複を含んでも含まなくてもよい非常に単純なJavaScript配列を持っています。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

重複を取り除き、一意の値を新しい配列に入れる必要があります。

私が試したすべてのコードを示すことはできますが、うまくいかないので無駄だと思います。私もjQueryソリューションを受け入れます。

同様の質問:

1086
kramden88

JQueryを使って素早く汚い:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
    if($.inArray(el, uniqueNames) === -1) uniqueNames.Push(el);
});
401
Roman Bataev

TL、DR

Set コンストラクタと spread構文 を使用します。

uniq = [...new Set(array)];

「スマート」だがナイーブな方法

uniqueArray = a.filter(function(item, pos) {
    return a.indexOf(item) == pos;
})

基本的に、配列を繰り返し処理し、各要素について、配列内のこの要素の最初の位置が現在の位置と等しいかどうかを確認します。明らかに、これら2つの位置は重複する要素では異なります。

フィルタコールバックの3番目( "this array")のパラメータを使用すると、配列変数のクローズを回避できます。

uniqueArray = a.filter(function(item, pos, self) {
    return self.indexOf(item) == pos;
})

簡潔ですが、このアルゴリズムは大きな配列(2次時間)では特に効率的ではありません。

ハッシュテーブルを助けに

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

これが通常のやり方です。アイデアは、各要素をハッシュテーブルに入れてから、その存在を即座に確認することです。これにより線形時間が得られますが、少なくとも2つの欠点があります。

  • ハッシュキーはJavaScriptでは文字列にしかなれないため、このコードでは数字と「数値文字列」を区別できません。つまり、uniq([1,"1"])[1]だけを返します。
  • 同じ理由で、すべてのオブジェクトは等しいと見なされます。uniq([{foo:1},{foo:2}])[{foo:1}]のみを返します。

ただし、配列にプリミティブのみが含まれていて、型を気にしない場合(たとえば常に数値)、この解決策が最適です。

二つの世界からの最高

ユニバーサルソリューションは、両方のアプローチを組み合わせたものです。プリミティブのハッシュルックアップとオブジェクトの線形検索を使用します。

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

    return a.filter(function(item) {
        var type = typeof item;
        if(type in prims)
            return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
        else
            return objs.indexOf(item) >= 0 ? false : objs.Push(item);
    });
}

並べ替え|独特

もう1つの選択肢は、最初に配列をソートしてから、前の要素と等しい各要素を削除することです。

function uniq(a) {
    return a.sort().filter(function(item, pos, ary) {
        return !pos || item != ary[pos - 1];
    })
}

繰り返しますが、これはオブジェクトに対しては機能しません(すべてのオブジェクトがsortに対して等しいため)。さらに、副作用として元の配列を黙って変更します。しかし、あなたの入力がすでにソートされているのなら、これが先です(上からsortを削除してください)。

でユニークな...

場合によっては、単なる等式以外の基準に基づいてリストを非公開にしたい場合があります。たとえば、異なるオブジェクトを除外し、何らかのプロパティを共有する場合などです。これはコールバックを渡すことでエレガントに実行できます。この「キー」コールバックは各要素に適用され、等しい「キー」を持つ要素は削除されます。 keyはプリミティブを返すことが期待されているので、ハッシュテーブルはここでうまく動きます:

function uniqBy(a, key) {
    var seen = {};
    return a.filter(function(item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    })
}

特に便利なkey()JSON.stringifyで、これは物理的には異なるが同じように見えるオブジェクトを削除します。

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
console.log(b) // [[1,2,3], [4,5,6]]

keyが原始的でない場合は、線形検索に頼らなければなりません:

function uniqBy(a, key) {
    var index = [];
    return a.filter(function (item) {
        var k = key(item);
        return index.indexOf(k) >= 0 ? false : index.Push(k);
    });
}

ES6では、Setを使用できます。

function uniqBy(a, key) {
    let seen = new Set();
    return a.filter(item => {
        let k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}

またはMap

function uniqBy(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

どちらも非プリミティブキーでも動作します。

最初か最後か

キーでオブジェクトを削除するときは、最初の "等しい"オブジェクトまたは最後のオブジェクトを保持することをお勧めします。

最初を保持するには上記のSetバリアントを使用し、最後を保持するにはMapを使用します。

function uniqByKeepFirst(a, key) {
    let seen = new Set();
    return a.filter(item => {
        let k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}


function uniqByKeepLast(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

//

data = [
    {a:1, u:1},
    {a:2, u:2},
    {a:3, u:3},
    {a:4, u:1},
    {a:5, u:2},
    {a:6, u:3},
];

console.log(uniqByKeepFirst(data, it => it.u))
console.log(uniqByKeepLast(data, it => it.u))

図書館

アンダースコアLo-Dash の両方にuniqメソッドがあります。それらのアルゴリズムは基本的に上記の最初のスニペットと似ており、これを要約します。

var result = [];
a.forEach(function(item) {
     if(result.indexOf(item) < 0) {
         result.Push(item);
     }
});

これは二次式ですが、ネイティブのindexOfをラッピングする、キーで一意化する能力(言い換えればiteratee)、および既にソート済みの配列の最適化など、その他にも便利な機能があります。

もしあなたがjQueryを使っていて、その前に何もしなければ何もできないのなら、それは次のようになります:

  $.uniqArray = function(a) {
        return $.grep(a, function(item, pos) {
            return $.inArray(item, a) === pos;
        });
  }

これもまた、最初のスニペットのバリエーションです。

パフォーマンス

関数呼び出しはJavaScriptでは高価であるため、上記のソリューションは、簡潔ではあるが特に効率的ではありません。最大限のパフォーマンスを得るには、filterをループに置き換えて、他の関数呼び出しを取り除きます。

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

この醜いコードの塊は上のスニペット#3と同じことをします、 しかし一桁速い (2017年の時点では、2倍の速さです。JSのコア担当者は素晴らしい仕事をしています。)

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

/////

var r = [0,1,2,3,4,5,6,7,8,9],
    a = [],
    LEN = 1000,
    LOOPS = 1000;

while(LEN--)
    a = a.concat(r);

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq(a);
document.write('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6では Set オブジェクトが提供されているので、作業がずっと簡単になります。

function uniq(a) {
   return Array.from(new Set(a));
}

または

let uniq = a => [...new Set(a)];

Pythonとは異なり、ES6セットは挿入順に繰り返されるため、このコードでは元の配列の順序が保持されます。

しかし、一意の要素を持つ配列が必要な場合は、最初からセットを使用しないでください。

ジェネレータ

"怠惰な"ジェネレータベースのuniqのバージョンも同じように構築できます。

  • 引数から次の値を取ります
  • すでに見たことがあれば、スキップしてください
  • そうでなければ、それを得て、それをすでに見られた値の集合にそれを追加する
function* uniqIter(a) {
    let seen = new Set();

    for (let x of a) {
        if (!seen.has(x)) {
            seen.add(x);
            yield x;
        }
    }
}

// example:

function* randomsBelow(limit) {
    while (1)
        yield Math.floor(Math.random() * limit);
}

// note that randomsBelow is endless

count = 20;
limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {
    console.log(r);
    if (--count === 0)
        break
}

// exercise for the reader: what happens if we set `limit` less than `count` and why
2803
georg

ForループやjQueryを使ってすべての悪い例を見てうんざりしました。 Javascriptには、今日、ソート、マップ、および縮小という、完璧なツールがあります。

既存の順序を維持しながらユニークな削減

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

var uniq = names.reduce(function(a,b){
    if (a.indexOf(b) < 0 ) a.Push(b);
    return a;
  },[]);

console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

// one liner
return names.reduce(function(a,b){if(a.indexOf(b)<0)a.Push(b);return a;},[]);

ソートによる一意性の向上

おそらくもっと速い方法がありますが、これはかなりまともです。

var uniq = names.slice() // slice makes copy of array before sorting it
  .sort(function(a,b){
    return a > b;
  })
  .reduce(function(a,b){
    if (a.slice(-1)[0] !== b) a.Push(b); // slice(-1)[0] means last item in array without removing it (like .pop())
    return a;
  },[]); // this empty array becomes the starting value for a

// one liner
return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.Push(b);return a;},[]);

更新2015:ES6のバージョン:

ES6には、セットとスプレッドがあり、すべての重複を簡単に削除できます。

var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

出現に基づいて並べ替えます。

いくつかのユニークな名前があることに基づいて結果を並べることについて誰かが尋ねました:

var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']

var uniq = names
  .map((name) => {
    return {count: 1, name: name}
  })
  .reduce((a, b) => {
    a[b.name] = (a[b.name] || 0) + b.count
    return a
  }, {})

var sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b])

console.log(sorted)
298

Vanilla JS:Setのようなオブジェクトを使って重複を削除する

あなたはいつでもそれをオブジェクトに入れて、それからそのキーを通して繰り返すことができます:

function remove_duplicates(arr) {
    var obj = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        obj[arr[i]] = true;
    }
    for (var key in obj) {
        ret_arr.Push(key);
    }
    return ret_arr;
}

Vanilla JS:すでに見られた値を追跡することで重複を削除する(オーダーセーフ)

あるいは、順序安全なバージョンの場合は、オブジェクトを使用して以前に確認されたすべての値を格納し、配列に追加する前にその値と照らし合わせて値を確認します。

function remove_duplicates_safe(arr) {
    var seen = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        if (!(arr[i] in seen)) {
            ret_arr.Push(arr[i]);
            seen[arr[i]] = true;
        }
    }
    return ret_arr;

}

ECMAScript 6:新しいSetデータ構造を使用する(順序安全)

ECMAScript 6では、新しいSet Data-Structureが追加されました。これにより、任意の型の値を格納できます。 Set.valuesは要素を挿入順に返します。

function remove_duplicates_es6(arr) {
    let s = new Set(arr);
    let it = s.values();
    return Array.from(it);
}

使用例:

a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

b = remove_duplicates(a);
// b:
// ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

c = remove_duplicates_safe(a);
// c:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

d = remove_duplicates_es6(a);
// d:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]
88
Casey Kuball

Underscore.jsを使用

これは配列を操作するための多数の関数を持つライブラリです。

それはjQueryのTuxとBackbone.jsのサスペンダーと一緒に行くことへの結びつきです。

_.uniq

_.uniq(array, [isSorted], [iterator])エイリアス: ユニーク
オブジェクトの等価性をテストするために===を使用して、 配列 の複製のないバージョンを作成します。 配列 がソートされていることを事前に知っている場合は、 isSorted trueを渡すと、はるかに高速なアルゴリズムが実行されます。変換に基づいて一意のアイテムを計算したい場合は、 イテレータ 関数を渡します。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

alert(_.uniq(names, false));

注: Lo-Dashアンダースコア 競合他社)も同等の .uniq 実装を提供します。

69
Brandon Boone

配列フィルタとindexOf関数を使った単一行バージョン:

arr = arr.filter (function (value, index, array) { 
    return array.indexOf (value) == index;
});
67
HBP

filterメソッドのsecond-index-parameterの助けを借りて、JavaScriptでそれを簡単に行うことができます。

var a = [2,3,4,5,5,4];
a.filter(function(value, index){ return a.indexOf(value) == index });

あるいは手短に言うと

a.filter((v,i) => a.indexOf(v) == i)
51
Ashutosh Jha

1行

let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);
45
Jonca33

ネイティブのJavaScript関数を使用して配列から重複を削除する最も簡潔な方法は、次のようなシーケンスを使用することです。

vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])

他の例で見たように、reduce関数内にsliceindexOfは必要ありません。ただし、フィルタ機能と一緒に使用するのは意味があります。

vals.filter(function(v, i, a){ return i == a.indexOf(v) })

ES6(2015)によるこれを実行するもう1つの方法は、すでにいくつかのブラウザで機能します。

Array.from(new Set(vals))

または spread演算子 を使用することもできます。

[...new Set(vals)]

乾杯!

32
Ivo

このようにArray.filter()を使う

var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana'];

console.log('Actual Array: ' + actualArr);

var filteredArr = actualArr.filter(function(item, index) {
  if (actualArr.indexOf(item) == index)
    return item;
});

console.log('Filtered Array: ' + filteredArr);

eS6ではこれを短くすることができます。

actualArr.filter((item,index,self) => self.indexOf(item)==index);

ここArray.filter()のいい説明です

26
Sumit Joshi

これに行きなさい:

var uniqueArray = duplicateArray.filter(function(elem, pos) {
    return duplicateArray.indexOf(elem) == pos;
}); 

UniqueArrayに重複はありません。

19
Juhan

最も簡単なものこれまでに遭遇した。 es6.

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl", "Mike", "Nancy"]

 var noDupe = Array.from(new Set(names))

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

18
Deke

私は他の質問で重複除去の詳細な比較をしました、しかし、これが私がちょうどそれをここでもそれを共有したい本当の場所であることに気付いたこと。

私はこれがこれを行うための最良の方法だと思います

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{}));
console.log(reduced);

OK ..これがO(n)で、他のものがO(n ^ 2)であっても、私はこのreduce/look-upテーブルとfilter/indexOfコンボのベンチマーク比較を見たかったです。 Jeetendras非常に素晴らしい実装 https://stackoverflow.com/a/37441144/4543207 )。 0から9999の範囲のランダムな正の整数で埋められた100Kのアイテム配列を準備して、それは重複を取り除きます。私はテストを10回繰り返しますが、結果の平均はそれらがパフォーマンスの点で一致していないことを示しています。

  • FirefoxのV47の削減&LUT:14.85ミリ秒対フィルタ&indexOf:2836ミリ秒
  • クロムv51では、&lutを減らす:23.90ms vs filter&indexOf:1066ms

まあ、これまでのところとても良い。しかし、今回はES6スタイルで正しく行いましょう。それはとてもクールに見えます..!しかし、今のところ、それがどのようにして強力なlut解決策に対して実行するのかは私にとって謎です。最初にコードを見て、次にそれをベンチマークすることができます。

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];
console.log(reduced);

うわーそれは短かった..!しかし、パフォーマンスはどうですか。それは美しいです... filter/indexOfの重さが私たちの肩の上に持ち上がったので、10個の連続したテストから平均を得るために0..99999の範囲の正の整数の配列1Mのランダム項目をテストできます。今回は本当の試合だと言えます。自分で結果を見てください:)

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 10;
for (var i = 0; i<count; i++){
  ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

どちらを使用しますか。それほど速くはありません…!だまされてはいけません。地図は移動中です。それでは、上記のすべてのケースで、サイズnの配列に範囲<nの数を入れます。サイズ100の配列があり、0..9の乱数が入っているので、明確な重複があり、「ほぼ」間違いなく各番号に重複があります。サイズ100の配列を乱数0..9999で埋めた場合はどうでしょうか。それでは、Mapが自宅で遊んでいるところを見てみましょう。今回は100Kアイテムの配列ですが、乱数の範囲は0..100Mです。結果を平均するために100回連続してテストを行います。さて、ベットを見てみましょう。 < - タイプミスなし

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

これがMap()の素晴らしい復活です。今なら、あなたは複製を削除したいときに、より良い決定を下すことができます。

さてさて、私たちはみな幸せです。しかし、主導的な役割は常に拍手を伴う最後に来ます。 Setオブジェクトが何をするのでしょうか。 ES6にオープンで、Mapが以前のゲームの勝者であることがわかったので、MapとSetをファイナルとして比較しましょう。今回の典型的なレアルマドリード対バルセロナの試合...それともそれ?誰がel classicoに勝つか見てみましょう:)

var ranar = [],
     red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     red2 = a => Array.from(new Set(a)),
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("map & spread took: " + avg1 + "msec");
console.log("set & A.from took: " + avg2 + "msec");

うわー..男..!意外にも、それはまったくエルクラシコであることが判明しませんでした。 CA Osasunaに対するBarcelona FCのようなもの:))

16
Redu

以下は、リストされているjQueryメソッドより80%以上高速です(下記のテストを参照)。それは数年前の同様の質問からの答えです。私が最初にそれを提案した人に出会ったら私は信用を投稿します。純粋なJS.

var temp = {};
for (var i = 0; i < array.length; i++)
  temp[array[i]] = true;
var r = [];
for (var k in temp)
  r.Push(k);
return r;

私のテストケースの比較: http://jsperf.com/remove-duplicate-array-tests

15
Levi

ECMAScript 6(別名ECMAScript 2015)では、 Set を使用して重複を除外で​​きます。その後、 spread演算子 を使用して、配列に戻すことができます。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"],
    unique = [...new Set(names)];
14
Oriol

解決策1

Array.prototype.unique = function() {
    var a = [];
    for (i = 0; i < this.length; i++) {
        var current = this[i];
        if (a.indexOf(current) < 0) a.Push(current);
    }
    return a;
}

解決策2(セットを使用)

Array.prototype.unique = function() {
    return Array.from(new Set(this));
}

テスト

var x=[1,2,3,3,2,1];
x.unique() //[1,2,3]

パフォーマンス

両方の実装(Setの有無にかかわらず)のパフォーマンスをクロムでテストしたところ、Setの方がはるかに速いことがわかりました。

Array.prototype.unique1 = function() {
    var a = [];
    for (i = 0; i < this.length; i++) {
        var current = this[i];
        if (a.indexOf(current) < 0) a.Push(current);
    }
    return a;
}


Array.prototype.unique2 = function() {
    return Array.from(new Set(this));
}

var x=[];
for(var i=0;i<10000;i++){
        x.Push("x"+i);x.Push("x"+(i+1));
}

console.time("unique1");
console.log(x.unique1());
console.timeEnd("unique1");



console.time("unique2");
console.log(x.unique2());
console.timeEnd("unique2");
14
ShAkKiR

これが質問に対する簡単な答えです。

var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"];
var uniqueNames = [];

    for(var i in names){
        if(uniqueNames.indexOf(names[i]) === -1){
            uniqueNames.Push(names[i]);
        }
    }
14
drew7721

単純だが効果的な方法は、フィルタfunction(value, index){ return this.indexOf(value) == index }と組み合わせてfilterメソッドを使うことです。

コード例:

var data = [2,3,4,5,5,4];
var filter = function(value, index){ return this.indexOf(value) == index };
var filteredData = data.filter(filter, data );

document.body.innerHTML = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

this Fiddle も参照してください。

10
John Slegers

これは特別なライブラリがない特別な関数ではない簡単な方法です

name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; })

console.log("Original name list:"+name_list.length, name_list)
console.log("\n Unique name list:"+get_uniq.length, get_uniq)

enter image description here

9

一番上の答えはO(n²)の複雑さを持っています、しかしこれはハッシュとしてオブジェクトを使うことによってちょうどO(n)ですることができます:

function getDistinctArray(arr) {
    var dups = {};
    return arr.filter(function(el) {
        var hash = el.valueOf();
        var isDup = dups[hash];
        dups[hash] = true;
        return !isDup;
    });
}

これは文字列、数値、そして日付に対して有効です。もしあなたの配列が複雑なオブジェクトを含んでいる(すなわちそれらは===と比較されなければならない)場合、上記の解決策は機能しません。オブジェクト自体にフラグを設定することで、オブジェクトのO(n)実装を得ることができます。

function getDistinctObjArray(arr) {
    var distinctArr = arr.filter(function(el) {
        var isDup = el.inArray;
        el.inArray = true;
        return !isDup;
    });
    distinctArr.forEach(function(el) {
        delete el.inArray;
    });
    return distinctArr;
}
9
gilly3

現在の答え(未来を見据えたES6のものを除く)よりも単純で簡潔なソリューションであることは別として、私はこれをperfテストしました、そしてそれは同様にはるかに高速でした:

var uniqueArray = dupeArray.filter(function(item, i, self){
  return self.lastIndexOf(item) == i;
});

1つの注意点:Array.lastIndexOf()がIE9で追加されたので、それよりも低くする必要がある場合は、他の場所を調べる必要があります。

8
csuwldcat

だからオプションは:

let a = [11,22,11,22];
let b = []


b = [ ...new Set(a) ];     
// b = [11, 22]

b = Array.from( new Set(a))   
// b = [11, 22]

b = a.filter((val,i)=>{
  return a.indexOf(val)==i
})                        
// b = [11, 22]
8
ofir_aghai

一般的な機能的アプローチ

ES2015を使用した一般的で厳密に機能的なアプローチは次のとおりです。

// small, reusable auxiliary functions

const apply = f => a => f(a);

const flip = f => b => a => f(a) (b);

const uncurry = f => (a, b) => f(a) (b);

const Push = x => xs => (xs.Push(x), xs);

const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const some = f => xs => xs.some(apply(f));


// the actual de-duplicate function

const uniqueBy = f => foldl(
   acc => x => some(f(x)) (acc)
    ? acc
    : Push(x) (acc)
 ) ([]);


// comparators

const eq = y => x => x === y;

// string equality case insensitive :D
const seqCI = y => x => x.toLowerCase() === y.toLowerCase();


// mock data

const xs = [1,2,3,1,2,3,4];

const ys = ["a", "b", "c", "A", "B", "C", "D"];


console.log( uniqueBy(eq) (xs) );

console.log( uniqueBy(seqCI) (ys) );

uniqueからunqiueByを簡単に派生させることも、Setsを利用してより高速な実装を使用することもできます。

const unqiue = uniqueBy(eq);

// const unique = xs => Array.from(new Set(xs));

このアプローチの利点:

  • 別のコンパレータ関数を使用した一般的な解決策
  • 宣言的で簡潔な実装
  • 他の小さな汎用関数を再利用する

パフォーマンスの考慮事項

uniqueByは、ループを使った命令型実装ほど速くはありませんが、その一般性のために、もっと表現力があります。

アプリのパフォーマンスが大幅に低下する原因としてuniqueByを特定した場合は、それを最適化されたコードに置き換えます。つまり、コードを最初に機能的で宣言的な方法で記述します。その後、パフォーマンスの問題が発生した場合は、問題の原因となっている場所でコードを最適化します。

メモリ消費とガベージコレクション

uniqueByはその体の中に隠された突然変異(Push(x) (acc))を利用します。それは各反復の後にそれを捨てる代わりにアキュムレータを再利用します。これにより、メモリ消費とGCの負荷が軽減されます。この副作用は関数内にラップされているので、外部のものはすべて純粋なままです。

7
user6445533
for (i=0; i<originalArray.length; i++) {  
    if (!newArray.includes(originalArray[i])) {
        newArray.Push(originalArray[i]); 
    }
}
5
MBJH

これは、(PhotoshopScriptでも)どこでもコードを理解して作業するための非常に簡単なものです。それをチェック!

var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");

peoplenames = unique(peoplenames);
alert(peoplenames);

function unique(array){
    var len = array.length;
    for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) 
        if(array[j] == array[i]){
            array.splice(j,1);
            j--;
            len--;
        }
    return array;
}

//*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"]
5
bodich
$(document).ready(function() {

    var arr1=["dog","dog","fish","cat","cat","fish","Apple","orange"]

    var arr2=["cat","fish","mango","Apple"]

    var uniquevalue=[];
    var seconduniquevalue=[];
    var finalarray=[];

    $.each(arr1,function(key,value){

       if($.inArray (value,uniquevalue) === -1)
       {
           uniquevalue.Push(value)

       }

    });

     $.each(arr2,function(key,value){

       if($.inArray (value,seconduniquevalue) === -1)
       {
           seconduniquevalue.Push(value)

       }

    });

    $.each(uniquevalue,function(ikey,ivalue){

        $.each(seconduniquevalue,function(ukey,uvalue){

            if( ivalue == uvalue)

            {
                finalarray.Push(ivalue);
            }   

        });

    });
    alert(finalarray);
});
4
user3840178

万が一使用していたら

D3.js

あなたはできる

d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]

https://github.com/mbostock/d3/wiki/Arrays#set_values

4
jetpackdata.com

カスタムコンパレータを使用するためのthg435の優れた答えを少し修正したものです。

function contains(array, obj) {
    for (var i = 0; i < array.length; i++) {
        if (isEqual(array[i], obj)) return true;
    }
    return false;
}
//comparator
function isEqual(obj1, obj2) {
    if (obj1.name == obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr, x) && arr.Push(x);
    });
}
3
vin_schumi

これはおそらく、配列から重複したものを永久に削除する最も速い方法の1つです ここのほとんどの関数の10倍の速さ。

function toUnique(a,b,c){               //array,placeholder,placeholder
 b=a.length;while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1)
}
  1. テスト: http://jsperf.com/wgu
  2. デモ: http://jsfiddle.net/46S7g/ /
  3. もっと: https://stackoverflow.com/a/25082874/2450730

上記のコードが読めない場合は、Javascriptの本を読むか、または短いコードに関する説明をご覧ください。 https://stackoverflow.com/a/21353032/2450730

3
cocco

ES6ソリューションが最も優れていますが、次のようなソリューションを誰も示していないことに困惑しています。

function removeDuplicates(arr){
    o={}
    arr.forEach(function(e){
        o[e]=true
    })
    return Object.keys(o)
}

ここで覚えておくべきことは、オブジェクトは一意のキーを持たなければならないということです。これを悪用して、すべての重複を削除します。私はこれが最速の解決策になると考えていたでしょう(ES6以前)。

ただしこれも配列をソートすることに注意してください。

3
Sancarn

https://jsfiddle.net/2w0k5tz8/ /

function remove_duplicates(array_){
    var ret_array = new Array();
    for (var a = array_.length - 1; a >= 0; a--) {
        for (var b = array_.length - 1; b >= 0; b--) {
            if(array_[a] == array_[b] && a != b){
                delete array_[b];
            }
        };
        if(array_[a] != undefined)
            ret_array.Push(array_[a]);
    };
    return ret_array;
}

console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3)));

配列インデックスは更新されないため、ループスルー、重複の削除、クローン配列のプレースホルダの作成を行います。

パフォーマンスを向上させるために逆方向にループします(ループは配列の長さをチェックし続ける必要はありません)。

3
THE AMAZING

これは別の解決策でしたが、他の解決策とは異なりました。

function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  newArr.sort();
  var finalArr = [];
  for(var i = 0;i<newArr.length;i++) {
   if(!(newArr[i] === newArr[i+1] || newArr[i] === newArr[i-1])) {
     finalArr.Push(newArr[i]);
   } 
  }
  return finalArr;
}
3
Isaac Pak

重複する要素を持つ配列を1つの一意の配列にフラット化しようとしている人のために:

function flattenUniq(arrays) {
  var args = Array.prototype.slice.call(arguments);

  var array = [].concat.apply([], args)

  var result = array.reduce(function(prev, curr){
    if (prev.indexOf(curr) < 0) prev.Push(curr);
    return prev;
  },[]);

  return result;
}
2
cjjenkinson

配列内の重複を取り除き、元の要素の順序を保持するためのネストループ法。

var array = [1, 3, 2, 1, [5], 2, [4]]; // INPUT

var element = 0;
var decrement = array.length - 1;
while(element < array.length) {
  while(element < decrement) {
    if (array[element] === array[decrement]) {
      array.splice(decrement, 1);
      decrement--;
    } else {
      decrement--;
    }
  }
  decrement = array.length - 1;
  element++;
}

console.log(array);// [1, 3, 2, [5], [4]]

説明:内部ループが、配列の最初の要素を、最も高いインデックスの要素から始まる他のすべての要素と比較します。最初の要素に向かって重複している要素を減分して配列から結合します。

内側のループが終了すると、外側のループは比較のために次の要素にインクリメントし、配列の新しい長さをリセットします。

1
y2knoproblem

あまりコードを記述せずにこれを実行するもう1つの方法は、ES5のObject.keys-メソッドを使用することです。

var arrayWithDuplicates = ['a','b','c','d','a','c'],
    deduper = {};
arrayWithDuplicates.forEach(function (item) {
    deduper[item] = null;
});
var dedupedArray = Object.keys(deduper); // ["a", "b", "c", "d"]

関数内に抽出

function removeDuplicates (arr) {
    var deduper = {}
    arr.forEach(function (item) {
        deduper[item] = null;
    });
    return Object.keys(deduper);
}
1
Willem de Wit

次のスクリプトは、一意の値のみを含む新しい配列を返します。文字列と数字に作用します。追加のライブラリを必要としないのはVanilla JSだけです。

ブラウザのサポート

Feature Chrome  Firefox (Gecko)     Internet Explorer   Opera   Safari
Basic support   (Yes)   1.5 (1.8)   9                   (Yes)   (Yes)

https://jsfiddle.net/fzmcgcxv/3/ /

var duplicates = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl","Mike","Mike","Nancy","Carl"]; 
var unique = duplicates.filter(function(elem, pos) {
    return duplicates.indexOf(elem) == pos;
  }); 
alert(unique);
1
GibboK
function arrayDuplicateRemove(arr){
    var c = 0;
    var tempArray = [];
    console.log(arr);
    arr.sort();
    console.log(arr);
    for (var i = arr.length - 1; i >= 0; i--) {
        if(arr[i] != tempArray[c-1]){
            tempArray.Push(arr[i])
            c++;
        }
    };
    console.log(tempArray);
    tempArray.sort();
    console.log(tempArray);
}
1
M.A.K. Ripon
const numbers = [1, 1, 2, 3, 4, 4];

function unique(array) {
  return array.reduce((a,b) => {
    let isIn = a.find(element => {
        return element === b;
    });
    if(!isIn){
      a.Push(b);
    }
    return a;
  },[]);
}

let ret = unique(numbers); // [1, 2, 3, 4]

reduceとfindの使い方.

1
gnujoow

重複を削除する最も簡単な方法は、forループを実行し、同じではない要素を比較してそれらを新しい配列にプッシュすることです。

 var array = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

 var removeDublicate = function(arr){
 var result = []
 var sort_arr = arr.sort() //=> optional
 for (var i = 0; i < arr.length; i++) {
        if(arr[ i + 1] !== arr[i] ){
            result.Push(arr[i])
        }
 };
  return result
}  
console.log(removeDublicate(array))
==>  ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]
0
user3449311

aLinksは単純なJavaScriptの配列オブジェクトです。重複レコードが削除されたことをインデックスが示す要素の前に要素が存在する場合。私はすべての重複を取り消すことを繰り返します。 1つのパッセージアレイがさらにレコードをキャンセルします。

var srt_ = 0;
var pos_ = 0;
do {
    var srt_ = 0;
    for (var i in aLinks) {
        pos_ = aLinks.indexOf(aLinks[i].valueOf(), 0);
        if (pos_ < i) {
            delete aLinks[i];
            srt_++;
        }
    }
} while (srt_ != 0);
0
stanislavs

Lodashを使って素早く簡単に - var array = ["12346","12347","12348","12349","12349"]; console.log(_.uniqWith(array,_.isEqual));

0
Anand Somani
var lines = ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Nancy", "Carl"];
var uniqueNames = [];

for(var i=0;i<lines.length;i++)
{
    if(uniqueNames.indexOf(lines[i]) == -1)
        uniqueNames.Push(lines[i]);
}
if(uniqueNames.indexOf(uniqueNames[uniqueNames.length-1])!= -1)
    uniqueNames.pop();
for(var i=0;i<uniqueNames.length;i++)
{
    document.write(uniqueNames[i]);
      document.write("<br/>");
}
0
Vishnu
function removeDuplicates(inputArray) {
            var outputArray=new Array();

            if(inputArray.length>0){
                jQuery.each(inputArray, function(index, value) {
                    if(jQuery.inArray(value, outputArray) == -1){
                        outputArray.Push(value);
                    }
                });
            }           
            return outputArray;
        }
0
realmag777
function removeDuplicates (array) {
  var sorted = array.slice().sort()
  var result = []

  sorted.forEach((item, index) => {
    if (sorted[index + 1] !== item) {
      result.Push(item)
    }
  })
  return result
}
0
Matt MacPherson

O(n)という複雑さを持つVanilla JSの解(この問題に対しては最も早い可能性があります)。必要に応じてオブジェクトを区別するためにhashFunctionを修正してください(例:1と "1")。最初の解決策は、(Arrayによって提供される関数で一般的な)隠されたループを避けます。

var dedupe = function(a) 
{
    var hash={},ret=[];
    var hashFunction = function(v) { return ""+v; };
    var collect = function(h)
    {
        if(hash.hasOwnProperty(hashFunction(h)) == false) // O(1)
        {
            hash[hashFunction(h)]=1;
            ret.Push(h); // should be O(1) for Arrays
            return;
        }
    };

    for(var i=0; i<a.length; i++) // this is a loop: O(n)
        collect(a[i]);
    //OR: a.forEach(collect); // this is a loop: O(n)

    return ret;
}

var dedupe = function(a) 
{
    var hash={};
    var isdupe = function(h)
    {
        if(hash.hasOwnProperty(h) == false) // O(1)
        {
            hash[h]=1;
            return true;
        }

        return false;
    };

    return a.filter(isdupe); // this is a loop: O(n)
}
0
cat

私は少し遅れてImを知っていますが、これは jinqJs を使った別のオプションです。

Fiddle を参照

var result = jinqJs().from(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]).distinct().select();
0
NYTom

重複文字列を削除する最も簡単な方法は、連想配列を使用してから、連想配列を反復処理してリスト/配列を元に戻すことです。

以下のように:

var toHash = [];
var toList = [];

// add from ur data list to hash
$(data.pointsToList).each(function(index, Element) {
    toHash[Element.nameTo]= Element.nameTo;
});

// now convert hash to array
// don't forget the "hasownproperty" else u will get random results 
for (var key in toHash)  {
    if (toHash.hasOwnProperty(key)) { 
      toList.Push(toHash[key]);
   }
}

出来上がりました、今重複がなくなりました!

0
nondescript

ライブラリ全体をインクルードしたくない場合は、これを使用して、任意の配列で使用できるメソッドを追加できます。

Array.prototype.uniq = function uniq() {
  return this.reduce(function(accum, cur) { 
    if (accum.indexOf(cur) === -1) accum.Push(cur); 
    return accum; 
  }, [] );
}

["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"].uniq()
0
Jonah

これがjQueryを使った別のアプローチです。

function uniqueArray(array){
  if ($.isArray(array)){
    var dupes = {}; var len, i;
    for (i=0,len=array.length;i<len;i++){
      var test = array[i].toString();
      if (dupes[test]) { array.splice(i,1); len--; i--; } else { dupes[test] = true; }
    }
  } 
  else {
    if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');
      return(array);
  }
  return(array);
}

著者: ウィリアムスキッドモア

0
Mathankumar
var duplicates = function(arr){
     var sorted = arr.sort();
   var dup = [];
   for(var i=0; i<sorted.length; i++){
        var rest  = sorted.slice(i+1); //slice the rest of array
       if(rest.indexOf(sorted[i]) > -1){//do indexOf
            if(dup.indexOf(sorted[i]) == -1)    
         dup.Push(sorted[i]);//store it in another arr
      }
   }
   console.log(dup);
}

duplicates(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]);
0
neelmeg
var uniqueCompnies = function(companyArray) {
    var arrayUniqueCompnies = [],
        found, x, y;

    for (x = 0; x < companyArray.length; x++) {
        found = undefined;
        for (y = 0; y < arrayUniqueCompnies.length; y++) {
            if (companyArray[x] === arrayUniqueCompnies[y]) {
                found = true;
                break;
            }
        }

        if ( ! found) {
            arrayUniqueCompnies.Push(companyArray[x]);
        }
    }

    return arrayUniqueCompnies;
}

var arr = [
    "Adobe Systems Incorporated",
    "IBX",
    "IBX",
    "BlackRock, Inc.",
    "BlackRock, Inc.",
];
0

このソリューションは新しい配列と関数内のオブジェクトマップを使います。元の配列をループ処理し、各整数をオブジェクトマップに追加するだけです。元の配列をループ処理している間は、繰り返しが発生します。

`if (!unique[int])`

これは、同じ番号のオブジェクトにすでにキープロパティがあるためです。したがって、その数をスキップして新しい配列にプッシュすることを許可しません。

    function removeRepeats(ints) {
      var unique = {}
      var newInts = []

      for (var i = 0; i < ints.length; i++) {
        var int = ints[i]

        if (!unique[int]) {
          unique[int] = 1
          newInts.Push(int)
        }
      }
      return newInts
    }

    var example = [100, 100, 100, 100, 500]
    console.log(removeRepeats(example)) // prints [100, 500]
0
Dan Zuzevich

自分で配列を作成している場合は、データを挿入するときにチェックを実行することで、ループと特別なフィルタを節約できます。

var values = [];
$.each(collection, function() {
    var x = $(this).value;
    if (!$.inArray(x, values)) {
        values.Push(x);
    }
});
0