JavaScriptの2つの配列をマージしてアイテムを重複排除する方法


1367

2つのJavaScript配列があります。

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

出力を次のようにしたい:

var array3 = ["Vijendra","Singh","Shakya"];

出力配列では、繰り返される単語が削除されているはずです。

JavaScriptで2つの配列をマージして、元の配列に挿入されたのと同じ順序で各配列から一意の項目のみを取得するにはどうすればよいですか?


1
新しい回答を投稿する前に、この質問にはすでに75以上の回答があることを考慮してください。回答が既存の回答に含まれない情報を提供していることを確認してください。
janniks

[... new Set([... [1、2、3]、... [2、3、4]])]結果[1、2、3、4]
Denis Giffeler

深いマージもカバーするより一般的なソリューションが必要な場合は、代わりにこの質問をご覧ください。いくつかの回答は配列もカバーしています。
マーティンブラウン

回答:


1665

(重複を削除せずに)配列をマージするには

ES5バージョンの使用Array.concat

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];

console.log(array1.concat(array2));

ES6バージョンは破壊を使用

const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];

重複を削除するための「組み込み」の方法がないため(ECMA-262には実際にArray.forEachこれが適しています)、手動で行う必要があります。

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
};

次に、それを使用するには:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique(); 

これにより、配列の順序も保持されます(つまり、並べ替えは不要です)。

多くの人はArray.prototypeand for inループのプロトタイプ拡張に悩まされているので、これを使用するための侵襲性の低い方法を次に示します。

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

    return a;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));

ES5を利用できるブラウザで作業できる幸運な人は、次のObject.definePropertyように使用できます。

Object.defineProperty(Array.prototype, 'unique', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }

        return a;
    }
});

281
このアルゴリズムはO(n ^ 2)であることに注意してください。
ガンボ

7
ましょう[a, b, c][x, b, d]配列で(引用符を想定)。concatは与える[a, b, c, x, b, d]。unique()の出力はになりません[a, c, x, b, d]。それは私が思う順序を維持しません-私はOPが望んでいると思います[a, b, c, x, d]
Amarghosh

89
OPは彼を働かせた最初の答えを受け入れ、それをサインオフしたようです。我々はまだ、お互いのソリューションを比較した障害-N-固定を見つけ、パフォーマンスの向上、上... stackoverflowの美しさの至る所ので、必ずその互換性を作っている:-)
Amarghosh

6
私は当初これに賛成票を投じましたが、私の考えを変えました。Array.prototypeにプロトタイプを割り当てると、「for ... in」ステートメントが壊れてしまいます。したがって、最善の解決策は、おそらくこのような関数を使用することですが、プロトタイプとして割り当てないことです。とにかく、配列要素を反復するために "for ... in"ステートメントを使用するべきではないと主張する人もいますが、多くの場合、それらをそのように使用するため、少なくともこのソリューションは慎重に使用してください。
コードコマンダー

16
あなたは常に使用すべきfor ... inhasOwnProperty、その場合には、プロトタイプの方法で結構です
mulllhausen

600

Underscore.jsまたはLo-Dashを使用すると、次のことができます。

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union


70
または、おそらくアンダースコアよりも優れたAPI互換のlodashです。
ブライアンM.ハント

3
@Ygg lodash docsから。「1つ以上の配列に存在する一意の値の新しい配列を順番に返します。」
Richard Ayotte 2013

4
私はunderscore.jsを好みます。私が最終的に使用したのはunderscore.flatten()、配列の配列を取るという点でunionよりも優れています。
織工

8
@weaver _.flattenはマージしますが、「重複排除」しません。
GijsjanB 2014年

9
lodashとトップの回答を比較したクイックパフォーマンス:jsperf.com/merge-two-arrays-keeping-only-unique-values
slickplaid

288

最初に2つの配列を連結し、次に一意のアイテムのみを除外します。

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

編集する

提案されているように、よりパフォーマンスに優れた解決策は、とb連結する前にの一意のアイテムを除外することaです。

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]


5
ここでの元のソリューションには、各ソースアレイ内の重複を削除するという利点があります。それはあなたが使うあなたの文脈に依存すると思います。
theGecko

IE6-supportの別のものをマージすることができます:c = Array.from(new Set(c));
Tobi G.

実際aにadd に変更したい場合b、ループしてプッシュを使用する方が良いでしょうか?a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
2016年

1
IE6を心配している人のために、現在のブラウザー使用状況caniuse.com/usage-tableを思い出させてください。
pmrotule 2016年

10
@Andrew:さらに良い:1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
7vujy0f0hy

203

これは、spread演算子と配列ジェネリックを使用するECMAScript 6ソリューションです。

現在、FirefoxとInternet Explorerのテクニカルプレビューでのみ機能します。

しかし、Babelを使用すれば、すぐに使用できます。

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));


14
これは受け入れられた回答に追加する必要があります。このソリューションは、現在可能なものよりもはるかに効率的でエレガントですが、必然的にできることです(この分野に追いつくためにすべきことです)。
EmmaGamma 2015年

これはOPの質問と同じではありませんが(これは何よりもフラットマップのように見えます)、すばらしいので賛成票を投じます。
jedd.ahyoung 2016

4
質問は2009年からなので、これは受け入れられる答えであるとは言えません。しかし、はい、これはより「パフォーマンス」だけでなく「エレガント」でもあります
Cezar Augusto

11
Array.fromスプレッド演算子の代わりに使用できます: Array.from(new Set([].concat(...arr)))
Henry Blyth

1
これはとてもエレガントです。残念ながら、Typescriptはまだこれをサポートしていません。stackoverflow.com/questions/33464504/...
ベン・カープ

190

ES6

array1.push(...array2) // => don't remove duplication 

または

[...array1,...array2] //   =>  don't remove duplication 

または

[...new Set([...array1 ,...array2])]; //   => remove duplication

1
第1 /第2の例では、何もありませんunion大型のスタックまでのすべての+の第一の例が吹く時にArray二つの中間以来、+ 3番目の例では、信じられないほど遅いのとメモリを大量に消費するArrayのは、ビルド+ 3番目の例では、だけのために使用することができますする必要がunion知られているとArrayコンパイル時のsの数。

それで、あなたはそれをどのように行いますか?
DavidNoreña16年

14
Setここに行くための方法です
philk '24 / 11/16

3
setは、同じオブジェクト参照でない限り、同じキーと値のペアを持つ2つのオブジェクトを重複排除できないことに注意してください。
Jun711、2018年

2
オブジェクト参照だけをマージし、オブジェクト自体が等しいかどうかを気にしないため、オブジェクトの配列では機能しません。
Wilson Biggs

87

セット(ECMAScript 2015)を使用すると、次のように簡単になります。

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
console.log(Array.from(new Set(array1.concat(array2))));


7
私はこれをES6を使用するための「承認された回答」と見なします。
mwieczorek 2018年

9
@mwieczorek方法:const array3 = [...new Set(array1.concat(array2))]
Robby Cornelissen

5
オブジェクトの配列を使用している場合は機能しません
carkod

1
複製せずに異なるオブジェクトをマージする場合:stackoverflow.com/a/54134237/3131433
Rakibul Haq

38

ループのテイクは少し異なります。Chromeの最新バージョンのいくつかの最適化により、2つの配列の結合(Chrome 38.0.2111)を解決する最も速い方法です。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

whileループ:〜589k ops / s
フィルター:〜445k ops / s
lodash:308k ops / s
forループ:225k ops / s

コメントは、書き込みのために空の配列を初期化する必要がなかったため、私のセットアップ変数の1つが私のループを他のループよりも先に進めていることを指摘しました。私はそれに同意するので、テストを公平な条件に書き直し、さらに高速なオプションを含めました。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/52

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

この代替ソリューションでは、1つの回答の連想配列ソリューションを組み合わせ.indexOf()て、2番目のループで速度を大幅に低下させていたループ内の呼び出しを排除し、他のユーザーが回答で提案した他の最適化もいくつか含めました。

ここでのすべての値(i-1)での二重ループの一番上の答えは、まだかなり遅いです。lodashは今でも強力に機能しており、プロジェクトにライブラリを追加することを気にしない人にはそれを勧めます。したくない人のために、私のwhileループはまだ良い答えであり、フィルターの答えはここで非常に強力に示され、この執筆時点での最新のCanary Chrome(44.0.2360)での私のテストすべてを打ち負かしています。

ワンランク上のスピードを上げたい場合は、マイクの回答ダンストッカーの回答を確認してください。これらは、実行可能な回答のほとんどすべてを通過した後、すべての結果の中で最速です。


方法論に問題があります。array3の作成をセットアップフェーズに入れますが、そのコストはwhileベースのソリューションのスコアの一部にすぎないはずです。この1行を移動すると、ソリューションはforループベースの速度に落ちます。配列は再利用できることを理解していますが、他のアルゴリズムでも、必要なすべてのビルディングブロックを宣言して初期化する必要がないことからもメリットが得られる可能性があります。
doldt 2015

私はあなたの前提@doldtに同意しますが、あなたの結果には同意しません。項目の削除後に配列の長さを再確認する必要があるという点で、ループベースのエントリの削除には根本的な設計上の欠陥があり、実行時間が長くなります。逆方向に動作するwhileループには、これらの影響はありません。元の回答をあまり変更せずに、できるだけ多くの設定変数を削除した例を次に示します。jsperf.com
two

@slickplaidリンクされたテストが空で、jsperfの次のリビジョンがwhileループでハングします。
doldt 2015

@doldt私は私の回答であなたの懸念に対処し、それに適切に更新されたテストを追加しました。これらの結果に同意するかどうかをお知らせください。また、連想配列を使用して別のより良い結果を追加しました。
slickplaid 2015

1
@slickplaid拡張perfページを設定していただきありがとうございます。何か不足している場合を除き、 "whileLoopAlt2"関数は機能しませんか?最初の配列と2番目の配列(逆順)を含む新しい配列を作成します。混乱を避けるために、壊れた関数を削除する別のリビジョンを作成しました。追加の例も追加しました:jsperf.com/merge-two-arrays-keeping-only-unique-values/22
Stephen S

37

ECMAScript 6で簡単に実行できます

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • 配列を連結するには、spread演算子を使用します。
  • 要素の個別のセットを作成するには、Setを使用します。
  • 再度、スプレッド演算子を使用して、セットを配列に変換します。

2
エラーが発生しました:タイプ 'Set <string>'は配列タイプではありません。
gattsbr 2016

3
また、何らかの理由でスプレッド演算子を使用したくない場合は、次のものもありますArray.from(new Set(array1.concat(array2)))
kba

@gattsbr、中に活字体でtsconfig.json、あなたは追加することができます"downlevelIteration": truecompilerOptions
VincentPerrin.com

19
Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

はるかに優れた配列マージ関数。


4
var test = ['a', 'b', 'c']; console.log(test); 印刷されます ["a", "b", "c", merge: function]
Doubidou

優れたソリューション。上記の@slickplaid(jsperf.com/merge-two-arrays-keeping-only-unique-values/3)によって投稿されたjsperfテストを更新しましたが、これが最も速いようです。
コブラ

@Cobra Chrome 40.0.2214(2015年2月18日時点で最新)で実行すると、ささいなことのように聞こえるかもしれませんが、この答えは私の答えより53%遅くなります。OTOH IE11は私の答えに最適化されていないようです。:)しかし、Chromeモバイルはまだそれを揺るがしています。正直なところ、私たちのほとんどが使用する必要があるlodash / _を使用している場合、真の答えはすでにこのリストのかなり上位にあります。:)
slickplaid 2015

@slickplaidTrue。lodash/ _と比較しても、かなり高速です。おそらく、実装をどこかであなたのものと似たものに切り替えることになるでしょう。:D
コブラ

1
indexOf()メソッドのコストがどの程度かはわかりませんが、これはおそらく最速のES5互換メソッドです。また、可変長の引数が不要であることにも価値があります。このメソッドは連鎖可能です。@slickplaidライブラリをロードすることは、「JavaScriptでそれを行う方法」の質問に対する答えにはなりません。確かに多くのライブラリには、この7行の作業を実行する機能があります。
18

19

ちょうど私の2セントを投入します。

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

これは私がよく使う方法で、オブジェクトをハッシュルックアップテーブルとして使用して重複チェックを行います。ハッシュがO(1)であると仮定すると、これはO(n)で実行され、nはa.length + b.lengthです。正直なところ、ブラウザーがハッシュをどのように処理するかはわかりませんが、何千ものデータポイントでうまく機能します。


とてもよくできました。連想配列を活用し、indexOfおよびその他の操作のループを回避することにより、このページの他の結果のすべてではないにしても、かなりの効果を発揮します。jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

あなたの「ハッシュ」はString()JavaScript の関数です。これはプリミティブ値に対しては機能しますが(型間の衝突はあります)、オブジェクトの配列には適していません。
ベルギ

私は同様のソリューションを使用して、hashCode関数または文字列を渡して、ハッシュキーとして使用するオブジェクトのプロパティを識別できるようにしています。
ロバートベイカー

19

入れ子のループ(O(n ^ 2))と.indexOf()(+ O(n))を避けてください。

function merge(a, b) {
    var hash = {}, i;
    for (i=0; i<a.length; i++) {
        hash[a[i]]=true;
    } 
    for (i=0; i<b.length; i++) {
        hash[b[i]]=true;
    } 
    return Object.keys(hash);
}

2
これは、特に文字列を実行している場合は、驚くべきことです。数値をそのままにするには、追加の手順が必要になります。この関数は、終了後にすべてが文字列であることを気にしない(または気にしない)場合、他のすべてのオプションを大幅に打ち負かします。良くやった。ここでのパフォーマンス結果:jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

18

この答えの最も簡単なものを簡略化し、それを素晴らしい関数に変えました:

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}

2
これは受け入れられた答えよりもずっときれいだと思います。また、フィルターは、現在かなりサポートされているECMAScript 5.1 +でサポートされているようです。
トムフォベア2017年

これは受け入れられるべき
でし

これは非常に簡潔です。
Mox

15

なぜオブジェクトを使わないのですか?セットをモデル化しようとしているようです。ただし、これは順序を保持しません。

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

どういう意味if (!set1.hasOwnProperty(key))ですか?
ガンボ

2
どういう意味ですか?その条件の目的は、オブジェクトのプロトタイプにある可能性のあるプロパティを無視することです。
Nick Retallack、

12

最良の解決策...

を押すと、ブラウザコンソールで直接確認できます...

重複なし

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

複製あり

["prince", "asish", 5].concat(["ravi", 4])

重複を避けたい場合は、ここからより良い解決策を試すことができます- 叫びコード

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

Chromeブラウザコンソールで試す

 f12 > console

出力:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

出力配列から重複を削除することはありません。
Shahar

9

私の1.5ペニー:

Array.prototype.concat_n_dedupe = function(other_array) {
  return this
    .concat(other_array) // add second
    .reduce(function(uniques, item) { // dedupe all
      if (uniques.indexOf(item) == -1) {
        uniques.push(item);
      }
      return uniques;
    }, []);
};

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var result = array1.concat_n_dedupe(array2);

console.log(result);

ES6の新機能は使用していませんが、見逃していませんか?
ベルギ

@ベルギ:はい、あなたは正しいです。注意していただきありがとうございます。どういうわけか私はこのスクリプトで遊んでおり、おそらくES6関数を備えたバージョンがいくつかありましたが、今では何世紀にもわたって存在するindexOfが含まれています。私の間違い、ごめんなさい。
Hero Qu

8

Underscore.jsの=> uniqを使用して簡単に実現できます。

array3 = _.uniq(array1.concat(array2))

console.log(array3)

["Vijendra"、 "Singh"、 "Shakya"]を印刷します。


7

ES6の場合、1行だけです。

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]

7

この質問はオブジェクトの配列に関するものではないことを知っていますが、サーチャーはここで終わります。

今後の読者のために、適切なES6の方法でマージしてから重複を削除することを追加する価値があります

オブジェクトの配列

var arr1 = [ {a: 1}, {a: 2}, {a: 3} ];
var arr2 = [ {a: 1}, {a: 2}, {a: 4} ];

var arr3 = arr1.concat(arr2.filter( ({a}) => !arr1.find(f => f.a == a) ));

// [ {a: 1}, {a: 2}, {a: 3}, {a: 4} ]

6
//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

indexOf他のブラウザーのメソッドの実装はMDCから取得されます


1
私はそれをw3schoolsで見つけることができなかったので、私はそれを書いたのです。w3schools.com/jsref/jsref_obj_array.aspそれはfromパラメーターを取りますか?
Amarghosh 2009年

@Gumboと@mederに感謝します。ブックマークを今すぐ変更します。私はまだjsで真剣に何もしていないし、カジュアルな参照のためにw3schoolsを使用しています(これが今までに必要だったすべてです)。
Amarghosh 2009年

MDCによると、indexOfにはjavascript 1.6が必要です。一般的なブラウザー(> = FF2、> IE6など)がそれをサポートすると想定しても安全ですか?
Amarghosh 2009年

4
IE6はArray.prototype.indexOfをサポートしていません。IEがエラーをスローしないように、Mozillaが提供するサポートメソッドを貼り付けてください。
meder omuraliev

を使用して更新されましたindexOf。コメント部分を削除してコードをクリーンアップしました。@meder-ありがとうございます。
Amarghosh 2009年

6

新しいソリューション(Array.prototype.indexOfおよびを使用Array.prototype.concat):

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

使用法:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

Array.prototype.indexOf(インターネットエクスプローラー用):

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

@Mender:順序は、私はこれを行う方法を、次に問題ではない場合
Vijjendra

1
Array.prototypeに対して定義されている標準のECMAScriptメソッドではありませんが、IEや、それをサポートしていない他のブラウザーに対して簡単に定義できることは承知しています。
meder omuraliev

このアルゴリズムはO(n ^ 2)であることに注意してください。
ガンボ

あなたの答えはどのアルゴリズムですか?
meder omuraliev

@meder:私のアルゴリズムはユニオンアルゴリズムです。ユニオン自体はO(n + m)で行われますが、並べ替えには最大でO(n・log n + m・log m)かかります。したがって、アルゴリズム全体はO(n・log n + m・log m)です。
ガンボ

6

Setを使用して行うことができます。

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);

//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
  temp text 
</div>


6

2つのアレイをマージするための非常に多くのソリューションがあります。それらは2つの主なカテゴリに分けることができます(lodashやunderscore.jsなどのサードパーティライブラリの使用を除く)。

a)2つの配列を結合し、重複する項目を削除します。

b)アイテムを組み合わせる前にフィルターで除外します。

2つの配列を結合し、重複するアイテムを削除する

組み合わせる

// mutable operation(array1 is the combined array)
array1.push(...array2);
array1.unshift(...array2);

// immutable operation
const combined = array1.concat(array2);
const combined = [...array1, ...array2];    // ES6

統一

配列を統合する方法はたくさんありますが、個人的には以下の2つの方法をお勧めします。

// a little bit tricky
const merged = combined.filter((item, index) => combined.indexOf(item) === index);
const merged = [...new Set(combined)];

組み合わせる前にアイテムを除外する

また、多くの方法がありますが、私はその単純さのために以下のコードを個人的に提案します。

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));

5
Array.prototype.add = function(b){
    var a = this.concat();                // clone current object
    if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
    if(!a.length) return b.concat();      // if original is empty, return b

    // go through all the elements of b
    for(var i = 0; i < b.length; i++){
        // if b's value is not in a, then add it
        if(a.indexOf(b[i]) == -1) a.push(b[i]);
    }
    return a;
}

// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]

5
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

これの良い点はパフォーマンスであり、一般に、配列を操作する場合、フィルターやマップなどのメソッドをチェーンしているため、その行を追加すると、後で参照することなく、array1とarray2を連結および重複排除できます。 1つ(あなたが持っていないメソッドを連鎖させているとき)、例:

someSource()
.reduce(...)
.filter(...)
.map(...) 
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc

(私はArray.prototypeを汚染したくないので、それがチェーンを尊重する唯一の方法です-新しい関数を定義するとそれが壊れます-したがって、私はこれを達成する唯一の方法だと思います)


4

あなたはこれを試すことができます:

const union = (a, b) => Array.from(new Set([...a, ...b]));

console.log(union(["neymar","messi"], ["ronaldo","neymar"]));


3

ES2015での機能的アプローチ

union2つArrayのsの機能的アプローチに従うと、concatとの構成になりfilterます。最適なパフォーマンスを提供するために、ネイティブに頼りますSet、プロパティルックアップ用に最適化されデータタイプを使用します。

とにかく、union関数に関連する重要な問題は、重複をどのように処理するかです。次の順列が可能です。

Array A      + Array B

[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

最初の2つの順列は、単一の関数で簡単に処理できます。ただし、最後の2つはSetルックアップに依存している限り処理できないため、より複雑です。プレーンな古いObjectプロパティルックアップに切り替えると、深刻なパフォーマンスヒットが発生するため、次の実装では3番目と4番目の順列を無視します。unionそれらをサポートするには、の個別のバージョンをビルドする必要があります。


// small, reusable auxiliary functions

const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// de-duplication

const dedupe = comp(afrom) (createSet);


// the actual union function

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];


// here we go

console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );

ここからunionnは、配列をいくつでも受け入れる関数を実装するのは簡単です(naomikのコメントに触発されました)。

// small, reusable auxiliary functions

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

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// union and unionn

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}

const unionn = (head, ...tail) => foldl(union) (head) (tail);


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];


// here we go

console.log( unionn(xs, ys, zs) );

それは判明unionnだけであるfoldl(別名Array.prototype.reduce)、とるunionその還元剤として。注:実装は追加のアキュムレータを使用しないため、引数なしで適用するとエラーがスローされます。


1
いくつかのフィードバック:私はそれに気づき、使用されflipていnotfません。また、unionBy述語リークの実装の詳細(Set型の暗黙的な知識が必要)。それはあなたがちょうどこのような何かを行うことができればいいことがありますunion = unionBy (apply)unionci = unionBy (p => x => p(x.toLowerCase()))。ユーザーはちょうどどんなグループ値を送信する方法があるにp^ _ ^ただアイデア-
あなたありがとうござい

zs変数の宣言にもvar/ letキーワードがありません
ありがとう

1
ここで明確にするコードスニペットです[要旨を:unionBy.jsは ]
ありがとう

@naomikしばらく私のソリューションを再考した後、述語を渡すのに正しい方法であるかどうかは、もうよくわかりません。得られるのは、2番目の配列の各要素の変換だけです。この方法で解決できるのはおもちゃの問題だけではないのでしょうか。

3

それのために...ここに単一行のソリューションがあります:

const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
// ['A', 'B', 'C']

特に読みやすいわけではありませんが、誰かを助けるかもしれません:

  1. アキュムレータの初期値を空の配列に設定して、reduce関数を適用します。
  2. reduce関数は、concatを使用して各サブ配列をアキュムレーター配列に追加します。
  3. この結果は、コンストラクタパラメータとして渡され、新しい Set
  4. スプレッド演算子は、 Set、を配列にます。
  5. sort()関数は、新しいアレイに適用されます。

2
また、代わりにreduce()使用できますArray.from(set)
Eran Goldin 2017

3

DeDuplicate singleまたはMerge and DeDuplicate multiple array input。以下の例。

ES6の使用-解体のための設定

複数の配列引数を取るこの単純な関数を書きました。上記のソリューションとほとんど同じですが、実際的な使用例があります。この関数は、重複した値を1つの配列のみに連結しないため、後の段階でそれらを削除できます。

短い関数の定義(9行のみ)

/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
   let set = new Set(); // init Set object (available as of ES6)
   for(let arr of args){ // for of loops through values
      arr.map((value) => { // map adds each value to Set object
         set.add(value); // set.add method adds only unique values
      });
   }
   return [...set]; // destructuring set object back to array object
   // alternativly we culd use:  return Array.from(set);
}

CODEPENの使用例:

// SCENARIO 
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = ['a','b','c','d'];
let e = ['b','c','d','e'];

// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);

// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]

なぜarr.mapここで使うのですか?foreach結果は無視されるため、これをとして使用しています
アントニー

私はreturn Array.from(set.values());を使用しました、vscodeはreturn [... set];
makkasi

3
var arr1 = [1, 3, 5, 6];
var arr2 = [3, 6, 10, 11, 12];
arr1.concat(arr2.filter(ele => !arr1.includes(ele)));
console.log(arr1);

output :- [1, 3, 5, 6, 10, 11, 12]

3

var array1 = ["one","two"];
var array2 = ["two", "three"];
var collectionOfTwoArrays = [...array1, ...array2];    
var uniqueList = array => [...new Set(array)];
console.log('Collection :');
console.log(collectionOfTwoArrays);    
console.log('Collection without duplicates :');
console.log(uniqueList(collectionOfTwoArrays));

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