JavaScript配列のすべての一意の値を取得します(重複を削除します)


1488

一意であることを確認する必要がある数値の配列があります。私はインターネットで以下のコードスニペットを見つけました。配列にゼロが含まれるまで、それはうまく機能します。Stack Overflowで、このスクリプトとほぼ同じように見えるこのスクリプトを見つけましたが、失敗しません。

それで、私が学ぶのを助けるために、誰かがプロトタイプスクリプトがどこで間違っているのかを判断するのを手伝ってくれる?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

重複した質問からのより多くの回答:

同様の質問:


3
@hippietrailその古い質問は、重複のみを見つけて返すことに関するものです(私も混乱していました!)。私の質問は、配列にゼロが含まれているときにこの関数が失敗する理由についての詳細です。
Mottie 2014

おそらく、質問のタイトルも曖昧にしたくないでしょう。
ヒッピートレイル2014

将来の読者のために、常にデータ構造のコンテンツをアルゴリズムで変更する(順序付けする、繰り返し要素を削除するなど)か、反復ごとにその内部の要素を検索する必要があることに気づき始めたら、あなたがそもそも間違ったデータ構造を使用していて、当面のタスクにより適切なデータ構造(この場合は配列ではなくハッシュセット)の使用を開始します。
nurettin 2014

私はどこか別の場所からコードをコピーしましたが、かなり前のことです...しかし、それはかなり簡単なようです:o= objecta= arrayi= indexおよびe= umm、何か:P
Mottie

回答:


2661

JavaScript 1.6 / ECMAScriptの5あなたはネイティブに使用できるfilter一意の値を持つ配列を取得するには、次のように配列する方法を:

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

ネイティブメソッドfilterは配列をループし、指定されたコールバック関数を渡すエントリのみを残しますonlyUnique

onlyUnique指定された値が最初に発生するかどうかを確認します。そうでない場合は、重複している必要があり、コピーされません。

このソリューションは、jQueryやprototype.jsのような追加のライブラリなしで機能します。

値型が混在する配列でも機能します。

古いブラウザ(<ie9)の場合、ネイティブメソッドfilterをサポートしていません。フィルターindexOfのindexOf MDNドキュメントで回避策を見つけることができます。

あなたが値の最後に出現を維持したい場合は、シンプルに置き換えるindexOfことでlastIndexOf

ES6を使用すると、次のように短縮できます。

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 

// unique is ['a', 1, 2, '1']

コメントのヒントを提供してくれたCamilo Martinに感謝します。

ES6には、Set一意の値を格納するためのネイティブオブジェクトがあります。一意の値を持つ配列を取得するには、次のようにします。

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)]; 

// unique is ['a', 1, 2, '1']

のコンストラクタはSet、Arrayなどの反復可能なオブジェクトを受け取り、spread演算子...はセットを配列に変換します。コメントのヒントを提供してくれたLukas Lieseに感謝します。


54
残念ながら、このソリューションは実行速度がかなり遅くなります。2回ループします。1回はフィルター、もう1回はインデックス
Jack Franzen '23

19
@JackFranzen何より遅い?ラファエルの解決策は?Rafaelsソリューションは、混合型配列では機能しません。私の例では、['a', 1, 'a', 2, '1']あなたは得るでしょう['a', 1, 2]。しかし、これは私が期待したものではありません。ところで、はるかに遅いのは非常に相対的です。
TLindig 2013年

25
最近のJSの場合:(.filter((v,i,a)=>a.indexOf(v)==i)太い矢印表記)。
Camilo Martin

164

5
最初の並べ替えやさまざまなデータ型の処理など、多くの可能性を含むより詳細な回答については、stackoverflow.com
a / 9229821/368896を

876

ES6 / ES2015の更新された回答Setを使用した単一行のソリューションは次のとおりです。

var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))

どっちが戻る

[4, 5, 6, 3, 2, 23, 1]

以下のようle_mが提案され、これはまた、使用して短縮することができスプレッド演算子をのような、

var uniqueItems = [...new Set(items)]

11
内側の配列は機能しないことに注意してくださいArray.from(new Set([[1,2],[1,2],[1,2,3]]))
Alexander Goncharov、

3
このソリューションのパフォーマンスと比較してmyArray.filter((v, i, a) => a.indexOf(v) === i);
Simoyw 2017年

43
Setプリミティブ値の代わりにを使用してオブジェクトを追加する場合、オブジェクトへの一意の参照が含まれることに注意してください。したがって、セットsインlet s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]);はこれを返します。Set { { Foo: 'Bar' }, { Foo: 'Bar' } }これはSet、同じ値を含むオブジェクトへの一意のオブジェクト参照を持つです。次のようにlet o = {Foo:"Bar"};2つの参照を持つセットを記述して作成するlet s2 = new Set([o,o]);と、s2はSet { { Foo: 'Bar' } }
mortb

2
これらのオプションのどちらでもpolyfill.io層が存在しているとIE10に問題がある
チミン

2
新しいテストケースjsperf.com/array-filter-unique-vs-new-set/1new Setsのトロフィーのようです
shuk

167

この質問にはすでに30以上の回答があることに気づきました。しかし、私は最初に既存のすべての答えを読み、自分で調査しました。

私は4つの可能な解決策へのすべての答えを分けます:

  1. 新しいES6機能を使用: [...new Set( [1, 1, 2] )];
  2. オブジェクト{ }を使用して重複を防止する
  3. ヘルパー配列を使用 [ ]
  4. 使用する filter + indexOf

回答にあるサンプルコードは次のとおりです。

新しいES6機能を使用: [...new Set( [1, 1, 2] )];

function uniqueArray0(array) {
  var result = Array.from(new Set(array));
  return result    
}

オブジェクト{ }を使用して重複を防止する

function uniqueArray1( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 

ヘルパー配列を使用 [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

使用する filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}

どっちが速いのかしら。関数をテストするためにサンプルのGoogleシートを作成しました。注:ECMA 6はGoogleスプレッドシートでは使用できないため、テストできません。

テストの結果は次のとおりです。 ここに画像の説明を入力してください

{ }ハッシュを使用しているため、object を使用するコードが勝つことを期待していました。テストがChromeとIEでこのアルゴリズムの最良の結果を示したことをうれしく思います。コードを提供しくれた@rabに感謝します


オプション「filter + indexOf」は、100.000項目を超える配列では非常に遅くなります。「オブジェクトマップ」アプローチを使用する必要がありましたが、元の並べ替えができなくなりました。
liberborn 2017

数値が大きいほど遅くなりますか?
fletchsod

3
@ fletchsod、数値はコードを実行するためのミリ秒単位の時間です。
Max Makhrov

1
数字がすごい!Googleアプリのスクリプトはクライアントのブラウザーではなくサーバー上で実行されるため、Chrome / IE(または実質的にすべてのブラウザー)でのパフォーマンスは同じになります。
Jay Dadhania

1
一方で、可能である(いずれかを経由してGoogleのスクリプトからクライアントサイドのJSを実行するためにgoogle.script.hostgoogle.script.run -いないことを確認する)、答えははっきりと述べている「ECMA 6 Googleスプレッドシートでavaliableではありません」 -したがって、投稿者がこのためにサーバー側のGoogleスクリプトを使用したと考えることができます。そのため、答えはブラウザではなくGoogleサーバーのパフォーマンスを示しています。
Jay Dadhania

134

underscore.jsを使用することもできます

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>

返されます:

[1, 2, 3, 4]

22
この人たちにしてください。Arrayプロトタイプに何かをジャックしないでください。お願いします。
Jacob Dalton

5
@JacobDalton-これはArrayプロトタイプを拡張していません。_オブジェクトで名前空間が設定されています。
スーパーミネラル

25
@superluminary私はそれが私これをてくださいと言った理由だと知ってます。受け入れられた解決策は、Arrayプロトタイプの変更を提案しています。それをしないでください。
Jacob Dalton 2016年

21
@JacobDaltonしないでください。で実行できる小さなジョブのためだけに、追加のライブラリを追加する必要はありませんarray = [...new Set(array)]

3
これは、ES機能を使用してライブラリを追加するという目的を打ち破り、Webサイトをさらに肥大化させました。
fletchsod

68

ワンライナー、ピュアJavaScript

ES6構文を使用

list = list.filter((x, i, a) => a.indexOf(x) == i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")

ここに画像の説明を入力してください

ES5構文を使用

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

ブラウザの互換性:IE9 +


14
@Spets二次コストを持っているので、それは最良の答えではありません
Oriol

@Spetsはすべての一意/一意を好みます...はい、賢く、最初に基数を使用してソートします。ほとんどの場合、0(n2)クイックサーチより遅くなります。
ドッカー、16

みんなありがとう!私が最初にコードを見たときはそれを理解していませんでしたが、今はもう少しわかりやすくなっています。
2016

51

それ以来、jQueryを使用する素晴らしいメソッドを見つけました

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});

注:このコードはPaul Irishのアヒルのパンチングポストから引用されました-クレジットを提供するのを忘れていました:P


8
簡潔なソリューションですが、inArrayの呼び出しは、hasOwnPropertyの呼び出しよりも効率がよくありません。
ミスタースミス

これもO(N ^ 2)ですよね?これに対して、辞書またはhasOwnPropertyアプローチはO(N * logN)になる可能性があります。
スピードプレーン2017

これは私にとってはうまくいきました、他のすべてのソリューションはInternet Explorerではサポートされていませんでした。
kerl

51

ES6での最短のソリューション: [...new Set( [1, 1, 2] )];

または、(元の質問のように)Arrayプロトタイプを変更する場合:

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};

EcmaScript 6は現在(2015年8月)の最新のブラウザーで部分的にのみ実装されていますが、BabelはES6(さらにはES7)をES5にトランスパイルすることで非常に人気があります。そうすれば、今すぐES6コードを書くことができます!

...意味がわからない場合は、スプレッド演算子と呼ばれます。MDNから:«スプレッド演算子を使用すると、複数の引数(関数呼び出しの場合)または複数の要素(配列リテラルの場合)が期待される場所で式を展開できます»。Setは反復可能であり(一意の値しか持てないため)、spreadオペレーターはSetを展開して配列を埋めます。

ES6を学ぶためのリソース:


3
あなたはそれをさらに短くすることができますa = [...Set(a)]が、とりあえずこれは今のところFirefoxのみです。
c69 14

@ c69、そうです、それより短くなることはありません。SpiderMonkeyユーザーにも感謝します。
Torsten Becker 14

バベルで動作します。あなただけのArray.fromシムも含める必要がありますrequire ( "core-js/fn/array/from" );
ウラジスラフRastrusny

Array.prototype.getUnique = function(){return [... new Set([this])]]である必要があります。}; または、Array.prototype.getUnique = function(){return [... new Set(this)]; }; $( 'body')。html()。toLowerCase()。match(/([a-zA-Z0-9 ._ +-] + @ [a-zA-Z0-9。 _-] + \。[a-zA-Z0-9 ._-] +)/ gi).getUnique(); 最初の1つは私に1つの一意の値のみを返し、2つ目はすべての重複を削除して再調整しました。
アシケ

[...Set(['a', 1, 'a', 2, '1'])]TypeErrorをスローするので、これを保持することは依然として賢明newです:[...new Set(['a', 1, 'a', 2, '1'])]
Adam Katz

36

最も簡単なソリューション:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);

または:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));


4
これはIE10以下ではサポートされていないことに注意してください。IE11 +およびSafariは限定的なサポート(もないことを確認して、上記の例の作品)を提供することを注意developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...は
oriadam

32

これを行う最も簡単で最速の(Chromeでの)方法:

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}

単に配列内のすべての項目を調べ、その項目がすでにリストにあるかどうかをテストし、ない場合は、返される配列にプッシュします。

jsPerfによると、この関数は私がどこでも見つけることができるものの中で最速です -自由に追加してください。

非プロトタイプバージョン:

function uniques(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

仕分け

配列の並べ替えも必要な場合は、次が最も高速です。

Array.prototype.sortUnique = function() {
    this.sort();
    var last_i;
    for (var i=0;i<this.length;i++)
        if ((last_i = this.lastIndexOf(this[i])) !== i)
            this.splice(i+1, last_i-i);
    return this;
}

または非プロトタイプ:

function sortUnique(arr) {
    arr.sort();
    var last_i;
    for (var i=0;i<arr.length;i++)
        if ((last_i = arr.lastIndexOf(arr[i])) !== i)
            arr.splice(i+1, last_i-i);
    return arr;
}

これは、ほとんどの非Chromeブラウザーで上記の方法より高速です


Linuxでは、Chrome 55.0.2883はarr.unique()を優先し、swilliamsのarrclone2.sortFilter()が最も遅い(78%遅い)。ただし、Firefox 51.0.0(多くのアドオンを含む)はswilliamsが最速(まだ他のChrome結果よりもOps / sec遅い)で、mottieのjQuery $ .grep(arr、jqFilter)が最も遅い(46%遅い)。あなたのarr.uniq()は30%遅くなりました。私は各テストを2回実行し、一貫した結果を得ました。Rafaelのarr.getUnique()が両方のブラウザで2位になりました。
Adam Katz

jsPerfは現時点ではバグがあるため、このテストを編集してもすべてがコミットされるわけではありませんでしたが、2つのテストが追加されました。両方のブラウザーでCoccoのtoUnique()がVamsiのES6 list.filter()を上回り、swilliamsのsortFilter()を破っています。 FFの#1の場合(sortFilterは16%遅い)、Chromeの#3の場合はソートされたテスト(2%遅い)に勝っています。
Adam Katz

ああ、私はそれらのテストが取るに足りないほど小さく、本当に重要ではないことを理解していませんでした。承認された回答へのコメントは、その問題説明し、テストの改訂版で修正を提供します。ラファエルのコードは簡単に最速で、Joetje50のarr.uniqueコードは98%遅いです。このコメントに記載されているように、別の改訂も行いました。
Adam Katz

1
さて、実際にunique関数で実装したアルゴリズムはO(n ^ 2)の複雑さを持っていますが、のアルゴリズムgetUniqueはO(n)です。最初のものは小さなデータセットでより高速かもしれませんが、数学とどのように議論することができますか:)後者を、たとえば1e5の一意の項目の配列で実行すると、より高速になることを確認できます
Mikhail Dudin

31

パフォーマンスのみ!このコードは、ここにあるすべてのコードよりもおそらく10倍速く *すべてのブラウザで機能し、メモリへの影響も最小限です。

古い配列を再利用する必要がない場合は、ここでそれを一意に変換する前に、必要な他の操作を行ってください。これはおそらくこれを行う最も速い方法ですが、これも非常に短い方法です。

var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];

その後、これを試すことができます

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];

function toUnique(a, b, c) { //array,placeholder,placeholder
  b = a.length;
  while (c = --b)
    while (c--) a[b] !== a[c] || a.splice(c, 1);
  return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]

私はこの記事を読んでこの機能を思いつきました...

http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

forループは好きではありません。多くのパラメータが必要です。whileループと同じです。whileは、すべてのブラウザで最も高速なループです。

とにかく、whileを使用する最初の関数を作成しました。そうです、記事にある関数よりも少し高速ですが、十分ではありません。unique2()

次のステップでは、モダンなjsを使用します。Object.keys 私はもう一方のforループをjs1.7のObject.keysに置き換えました...少し速くて短い(クロムでは2倍速い);)。十分ではない!。unique3()

この時点で、私のユニークな機能に本当に必要なものについて考えていました。古い配列は必要ありません。高速な関数が必要です。したがって、2つのwhileループ+スプライスを使用しました。unique4()

感動したと言ってもダメ。

クロム:通常の1秒あたり150,000オペレーションは、1秒あたり1,800,000オペレーションにジャンプしました。

つまり、 80,000 op / s対3,500,000 op / s

iOS: 18,000 op / s対170,000 op / s

サファリ: 80,000オペレーション/秒vs 6,000,000オペレーション/秒

証明 http://jsperf.com/wguまたはより適切にconsole.time ... microtime ...を使用してください

unique5() 古い配列を保持したい場合にどうなるかを示すだけです。

あなたArray.prototypeが何をしているかわからない場合は使用しないでください。たくさんのコピーと過去をやりました。Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})ネイティブプロトタイプを作成する場合に使用します。例:https : //stackoverflow.com/a/20463021/2450730

デモ http://jsfiddle.net/46S7g/

注:この操作の後、古いアレイは破棄されるか、固有のものになります。

上記のコードが読めない場合は、javascriptの本を読んでください。短いコードについての説明もいくつかあります。https://stackoverflow.com/a/21353032/2450730

一部は使用indexOf しています... 使用しない... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

空の配列の場合

!array.length||toUnique(array); 

4
url(文字列)の100k配列を使用してnode.jsでテストされています。結果はunderscore.js _.uniqより2倍遅くなりました...別のjsperfがあなたに同意しますが(jsperf.com/uniq-performance/5)、私は失望しました:(
xShirase

3
あなたはjsperfで正しくテストしていない...あなたの例では毎回関数を定義しています...しかし、underscore.js関数はすでに定義されています。これは私の関数にペナルティを課します。また、3と4をテストします。もう1つ言うべきことは、混合変数(文字列と数値)を使用する場合は、a [b]!== a [c]をa [b]!= a [c]に置き換える必要があるということです
cocco

2
jsPerfが正しいかどうかはわかりませんが、Reduceの代替案(私にとっては理解しやすい)は、ソリューションよりも94%速いと思われます。jsperf.com/reduce-for-distinct編集:Chromeの方が遅く、Edgeでは同じで、Firefoxでは高速です。
Victor Ivens 2017

3
小さなアレイ/低い重複率でのみ使用できます。一意でないオブジェクトが見つかるたびに、エンジンは残りのすべての要素を左にシフトするように強制されます:1)それらを反復処理する2)それらを読み取る3)新しい場所に書き込む そして、その1つのスプライスされた要素で新しい配列作成し、結果としてそれを返します...アルゴリズムは、より大きな配列/より頻繁な複製で急速に低下します。サイズが1000-> 10000-> 50000で重複が最大40%のアレイの場合、平均所要時間は2-> 775-> 19113 msのようになります。(サイズは1-> x10-> x5に変更され、時間は1-> x10-> x25に変更されます)Chromeで。
アンクゼット2017年

1
ありがとう。素敵なアプローチ。しかし、正しいアイテムの注文はどうですか?
liberborn 2017

28

ここでの答えの多くは初心者には役に立たないかもしれません。配列の重複排除が難しい場合、プロトタイプチェーン、またはjQueryについて本当に知っているでしょうか?

最近のブラウザーでは、クリーンでシンプルなソリューションは、一意の値のリストになるように設計されたSetにデータを格納することです。

const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));

Array.from配列は持っていることをあなたは素晴らしい方法のすべて(の機能)への容易なアクセスを持っているので、配列に設定背中を変換するのに便利です。同じことを行う他の方法もあります。ただしArray.from、セットにはforEachなどの便利な機能がたくさんあるため、まったく必要ない場合もあります。

古いInternet Explorerをサポートする必要があるためSetを使用できない場合、簡単な方法は、項目が新しい配列にすでにあるかどうかを事前に確認しながら、新しい配列にコピーすることです。

// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];

// Go through each car, one at a time.
cars.forEach(function (car) {
    // The code within the following block runs only if the
    // current car does NOT exist in the uniqueCars list
    // - a.k.a. prevent duplicates
    if (uniqueCars.indexOf(car) === -1) {
        // Since we now know we haven't seen this car before,
        // copy it to the end of the uniqueCars list.
        uniqueCars.push(car);
    }
});

これを即座に再利用可能にするために、関数に入れましょう。

function deduplicate(data) {
    if (data.length > 0) {
        var result = [];

        data.forEach(function (elem) {
            if (result.indexOf(elem) === -1) {
                result.push(elem);
            }
        });

        return result;
    }
}

重複を取り除くために、これを実行します。

var uniqueCars = deduplicate(cars);

関数が完了する、そのdeduplicate(cars)部分resultという名前になります。

好きな配列の名前を渡してください。


ちなみに、文字列でいっぱいの配列を使用して、自分の手法が柔軟であることを示しました。数値に対しては適切に機能します。
Seth Holladay、2014年

20
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

push使用する代わりに、単に要素を配列に入れなかった理由を説明できますconcatか?プッシュを使用してみましたが失敗しました。説明を探しています。
makenova 2015

1
その理由は戻り値にあります。concatは変更された配列(reduce関数内で返す必要があるもの)を返しますが、pushはプッシュされた値にアクセスできるインデックスを返します。それはあなたの質問に答えますか?
sergeyz

どうやら、このソリューションはクローム(およびノー​​ド)で非常に高速です。jsperf.com/reduce-for-distinct ES6バージョンだこと: [0,1,2,0,3,2,1,5].reduce((prev, cur) => ~prev.indexOf(cur) ? prev : prev.concat([cur]), []);
ビクターイヴェンス

補足:この実装はNaN友好的ではありません
Alireza

19

ES6セットを使用してこれを行うことができます。

var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));

console.log(uniqueArray);

//出力は

uniqueArray = [1,2,3,4,5];

17

このプロトタイプgetUniqueは完全に正しくはありません。なぜなら、もし私が次のような配列を持っている場合、["1",1,2,3,4,1,"foo"]それは返され["1","2","3","4"]"1"文字列で1あり、整数です。彼らは違う。

これが正しい解決策です:

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });

使用:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

上記により生産され["1",2,3,4,1,"foo"]ます。


1
これ$foo = 'bar'は、PHPが変数を宣言する方法です。これはJavaScriptで機能しますが、暗黙のグローバルを作成するため、通常は実行しないでください。
カミロマーティン

@CamiloMartin申し訳ありませんが、間違いです。$ fooはグローバルです。これは、例がクロージャーになく、varキーワードがないためです。ドルとは関係ありませんjsfiddle.net/robaldred/L2MRb
Rob

8
@Robそれはまさに私が言っていることです。PHPの人々は$foo、JavaScriptで実際に変数を宣言する方法だと考えるでしょうvar foo
Camilo Martin

13

Array.prototypeを拡張しない(悪い習慣と言われています)か、jquery / underscoreを使用せずに、単純filterに配列を作成できます。

最後の発生を維持することにより:

    function arrayLastUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps last occurrence
            return c.indexOf(a, b + 1) < 0;
        });
    },

または最初の発生:

    function arrayFirstUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps first occurrence
            return c.indexOf(a) === b;
        });
    },

まあ、それはIE9 +のみを意味するJavaScript ECMAScript 5+だけですが、ネイティブHTML / JS(Windowsストアアプリ、Firefox OS、Sencha、Phonegap、Titaniumなど)での開発には適しています。


2
js 1.6であるということは、を使用できないことを意味するものではありませんfilterMDNページには、Internet Explorer、つまり古いブラウザの実装があります。また:JS 1.6はFirefoxのJSエンジンを指し、それはそれはECMAScriptの5であることだと言うには正しいこと
カミロ・マーティン

@CamiloMartin 1.6をECMAScript5に変更しました。ありがとう。
2013年

13

マジック

a.filter(e=>!(t[e]=e in t)) 

O(n) パフォーマンス ; 私たちは、あなたの配列がであると仮定aしてt={}ここで説明(+ Jeppe impr。)


14
超クールなので、この一見、私はこれを実行したときに、私はあなたにしているつもり鉱山bitcoinsを落ちた固形説明せずにその
オンドレイŽelazko

3
私が意味したことは、あなたはいくつかの説明とそれのコメントされた解体であなたの答えを広げるべきだということです。人々がこのような有用な答えを見つけることを期待しないでください。(けれどもそれは本当に、おそらく作品クールに見える)
オンドレイŽelazko

1
@Jeppe私があなたの改善を実行するとき、私はaha効果を経験します(ループin以外の構造の外で演算子を使用できることを知らない前にfor:P)-ありがとうございます-私はそれを感謝し、あなたの他の良い答えに+2を与えます。
KamilKiełczewski19年

2
tそれは、フィルタリング後も存続するグローバル変数を作成しません…??
フィリップ

1
これは本当にトリッキーなソリューションです。残念ながら、グローバル変数を定義したり、グローバルを非表示にするためにモジュールバンドルに依存したりしない場合を除き、式の外側でtを宣言する必要があります。見た目は豪華ですが、自分(および開発チーム)に好意を示し、2つのライナーを書くだけです。let t = {}; a.filter(e =>!(t [e] = e in t))
ford04

13
[...new Set(duplicates)]

これは最も単純なものであり、MDN Web Docsから参照されています

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]

このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明を含めると、投稿の品質が向上し、おそらく投票数が増えることになります。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
id.ot

11

Prototypeフレームワークを使用している場合は、「for」ループを実行する必要はありません。次のようにhttp://www.prototypejs.org/api/array/uniqを使用できます

var a = Array.uniq();  

これにより、重複のない重複配列が生成されます。個別の配列レコードをカウントする方法を検索する質問に出くわしたので、

uniq()

使った

サイズ()

そして私の簡単な結果がありました。ps何かタイプミスした場合は申し訳ありません

編集:未定義のレコードをエスケープしたい場合は、追加することができます

コンパクト()

以前は、このように:

var a = Array.compact().uniq();  

14
私はより良い答えを見つけたので、トピックについては、質問した人だけでなくすべての人のためだと思います
Decebal

11

セットを使用して、重複を削除し、配列に戻すことができます。

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

console.log([...new Set(names)])

別の解決策は、ソートとフィルターを使用することです

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);


10

それ0は、JavaScriptの偽の値だからです。

this[i] 配列の値が0またはその他の偽の値である場合、偽になります。


ああ、わかりました。わかりました...しかし、それを機能させる簡単な修正はありますか?
Mottie、

10
Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}

配列にオブジェクト/配列が含まれている場合、これは機能しないと思います。スカラーのタイプを保持するかどうかはわかりません。
Camilo Martin

はい、すべてが文字列化されます。これはo、単なるの代わりに元の値を格納することで修正できますが1、等価比較は文字列ごとに行われます(ただし、考えられるすべてのJavascriptの等価のうち、不当に見えることはありません)。
エフェミエント2013年

Array.prototypeは、列挙不可能なメソッドでのみ拡張できます.... Object.defineProperty(Array.prototype、 "getUnique"、{})...しかし、ヘルパーオブジェクトを使用するという考えは非常に優れています
bortunac

10

重複するidプロパティを持つオブジェクトを配列から削除する必要がある、少し異なる問題がありました。これはうまくいきました。

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);


9

最も簡単な答えは:

const array = [1, 1, 2, 2, 3, 5, 5, 2];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 5]

単純ですが、オブジェクトの配列では機能しません。
Thanwa Ch。

7

Gabriel Silveiraがこのように関数を記述した理由はわかりませんが、縮小化なしでも機能する単純な形式は次のとおりです。

Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};

またはCoffeeScriptで:

Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )

7

追加の依存関係に問題がない場合、またはコードベースにすでにライブラリの1つがある場合は、LoDash(またはアンダースコア)を使用して配列から重複を削除できます。

使用法

コードベースにまだない場合は、npmを使用してインストールします。

npm install lodash

次に、次のように使用します。

import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);

アウト:

[ 1, 2, 3 ]

7

これは多くの回答を得ましたが、私の特定のニーズには対応していませんでした。

多くの答えはこのようなものです:

a.filter((item, pos, self) => self.indexOf(item) === pos);

しかし、これは複雑なオブジェクトの配列に対しては機能しません。

次のような配列があるとします。

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];

一意の名前のオブジェクトが必要な場合array.prototype.findIndexは、array.prototype.indexOf次の代わりに使用する必要があります。

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);

優れたソリューションです。新しい配列が関数から返されることに注意してください。(それ自体は変更されません)
Thanwa Ch。

6

Shamasisバッタチャリヤのブログ(O(2N)時間複雑):

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

ポール・アイリッシュのブログ:jQueryの上の改善.unique()

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

6

単純な方法で一意の配列値を見つける

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]

6

数年間、受け入れられた回答であったラファエルの回答を失ったようです。これは(少なくとも2017年には)混合タイプの配列がない場合に最適なソリューションでした

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}

あなたがいる場合行う混合型の配列を持っている、あなたは、ハッシュキーをシリアル化することができます:

Array.prototype.getUnique = function() {
    var hash = {}, result = [], key; 
    for ( var i = 0, l = this.length; i < l; ++i ) {
        key = JSON.stringify(this[i]);
        if ( !hash.hasOwnProperty(key) ) {
            hash[key] = true;
            result.push(this[i]);
        }
    }
    return result;
}

5

逆の方法で問題に対処するには、配列をロードするときに重複がないようにすると便利です。Setオブジェクトが行う方法と同じですが、まだすべてのブラウザーで使用できるわけではありません。それはメモリを節約し、その内容を何度も見る必要がある場合により効率的です。

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}

サンプル:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });

あなたにあげる set = [1,3,4,2]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.