私は重複を含んでも含まなくてもよい非常に単純なJavaScript配列を持っています。
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
重複を取り除き、一意の値を新しい配列に入れる必要があります。
私が試したすべてのコードを示すことはできますが、うまくいかないので無駄だと思います。私もjQueryソリューションを受け入れます。
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);
});
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つの欠点があります。
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では 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
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;},[]);
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)
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"]
これは配列を操作するための多数の関数を持つライブラリです。
それはjQueryのTuxとBackbone.jsのサスペンダーと一緒に行くことへの結びつきです。
_.uniq(array, [isSorted], [iterator])
エイリアス: ユニーク
オブジェクトの等価性をテストするために===を使用して、 配列 の複製のないバージョンを作成します。 配列 がソートされていることを事前に知っている場合は、 isSorted にtrueを渡すと、はるかに高速なアルゴリズムが実行されます。変換に基づいて一意のアイテムを計算したい場合は、 イテレータ 関数を渡します。
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
alert(_.uniq(names, false));
配列フィルタとindexOf関数を使った単一行バージョン:
arr = arr.filter (function (value, index, array) {
return array.indexOf (value) == index;
});
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)
1行
let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);
ネイティブのJavaScript関数を使用して配列から重複を削除する最も簡潔な方法は、次のようなシーケンスを使用することです。
vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])
他の例で見たように、reduce関数内にslice
やindexOf
は必要ありません。ただし、フィルタ機能と一緒に使用するのは意味があります。
vals.filter(function(v, i, a){ return i == a.indexOf(v) })
ES6(2015)によるこれを実行するもう1つの方法は、すでにいくつかのブラウザで機能します。
Array.from(new Set(vals))
または spread演算子 を使用することもできます。
[...new Set(vals)]
乾杯!
このように
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()
のいい説明です
これに行きなさい:
var uniqueArray = duplicateArray.filter(function(elem, pos) {
return duplicateArray.indexOf(elem) == pos;
});
UniqueArrayに重複はありません。
最も簡単なものこれまでに遭遇した。 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
私は他の質問で重複除去の詳細な比較をしました、しかし、これが私がちょうどそれをここでもそれを共有したい本当の場所であることに気付いたこと。
私はこれがこれを行うための最良の方法だと思います
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回繰り返しますが、結果の平均はそれらがパフォーマンスの点で一致していないことを示しています。
まあ、これまでのところとても良い。しかし、今回は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のようなもの:))
以下は、リストされている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
解決策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");
これが質問に対する簡単な答えです。
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]);
}
}
単純だが効果的な方法は、フィルタ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 も参照してください。
これは特別なライブラリがない特別な関数ではない簡単な方法です
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)
一番上の答えは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;
}
現在の答え(未来を見据えたES6のものを除く)よりも単純で簡潔なソリューションであることは別として、私はこれをperfテストしました、そしてそれは同様にはるかに高速でした:
var uniqueArray = dupeArray.filter(function(item, i, self){
return self.lastIndexOf(item) == i;
});
1つの注意点:Array.lastIndexOf()がIE9で追加されたので、それよりも低くする必要がある場合は、他の場所を調べる必要があります。
だからオプションは:
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]
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
を簡単に派生させることも、Set
sを利用してより高速な実装を使用することもできます。
const unqiue = uniqueBy(eq);
// const unique = xs => Array.from(new Set(xs));
このアプローチの利点:
uniqueBy
は、ループを使った命令型実装ほど速くはありませんが、その一般性のために、もっと表現力があります。
アプリのパフォーマンスが大幅に低下する原因としてuniqueBy
を特定した場合は、それを最適化されたコードに置き換えます。つまり、コードを最初に機能的で宣言的な方法で記述します。その後、パフォーマンスの問題が発生した場合は、問題の原因となっている場所でコードを最適化します。
uniqueBy
はその体の中に隠された突然変異(Push(x) (acc)
)を利用します。それは各反復の後にそれを捨てる代わりにアキュムレータを再利用します。これにより、メモリ消費とGCの負荷が軽減されます。この副作用は関数内にラップされているので、外部のものはすべて純粋なままです。
for (i=0; i<originalArray.length; i++) {
if (!newArray.includes(originalArray[i])) {
newArray.Push(originalArray[i]);
}
}
これは、(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"]
$(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);
});
万が一使用していたら
D3.js
あなたはできる
d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]
カスタムコンパレータを使用するための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);
});
}
これはおそらく、配列から重複したものを永久に削除する最も速い方法の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)
}
上記のコードが読めない場合は、Javascriptの本を読むか、または短いコードに関する説明をご覧ください。 https://stackoverflow.com/a/21353032/2450730
ES6ソリューションが最も優れていますが、次のようなソリューションを誰も示していないことに困惑しています。
function removeDuplicates(arr){
o={}
arr.forEach(function(e){
o[e]=true
})
return Object.keys(o)
}
ここで覚えておくべきことは、オブジェクトは一意のキーを持たなければならないということです。これを悪用して、すべての重複を削除します。私はこれが最速の解決策になると考えていたでしょう(ES6以前)。
ただしこれも配列をソートすることに注意してください。
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)));
配列インデックスは更新されないため、ループスルー、重複の削除、クローン配列のプレースホルダの作成を行います。
パフォーマンスを向上させるために逆方向にループします(ループは配列の長さをチェックし続ける必要はありません)。
これは別の解決策でしたが、他の解決策とは異なりました。
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;
}
重複する要素を持つ配列を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;
}
配列内の重複を取り除き、元の要素の順序を保持するためのネストループ法。
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つの方法は、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);
}
次のスクリプトは、一意の値のみを含む新しい配列を返します。文字列と数字に作用します。追加のライブラリを必要としないのは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);
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);
}
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の使い方.
重複を削除する最も簡単な方法は、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"]
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);
Lodashを使って素早く簡単に - var array = ["12346","12347","12348","12349","12349"]; console.log(_.uniqWith(array,_.isEqual));
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/>");
}
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;
}
function removeDuplicates (array) {
var sorted = array.slice().sort()
var result = []
sorted.forEach((item, index) => {
if (sorted[index + 1] !== item) {
result.Push(item)
}
})
return result
}
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)
}
重複文字列を削除する最も簡単な方法は、連想配列を使用してから、連想配列を反復処理してリスト/配列を元に戻すことです。
以下のように:
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]);
}
}
出来上がりました、今重複がなくなりました!
ライブラリ全体をインクルードしたくない場合は、これを使用して、任意の配列で使用できるメソッドを追加できます。
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()
これが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);
}
著者: ウィリアムスキッドモア
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"]);
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.",
];
このソリューションは新しい配列と関数内のオブジェクトマップを使います。元の配列をループ処理し、各整数をオブジェクトマップに追加するだけです。元の配列をループ処理している間は、繰り返しが発生します。
`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]
自分で配列を作成している場合は、データを挿入するときにチェックを実行することで、ループと特別なフィルタを節約できます。
var values = [];
$.each(collection, function() {
var x = $(this).value;
if (!$.inArray(x, values)) {
values.Push(x);
}
});