Как объединить два массива в JavaScript и дедублировать элементы

У меня есть два массива JavaScript:

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

Я хочу, чтобы выход был:

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

Выходной массив должен иметь повторяющиеся слова.

Как объединить два массива в JavaScript, чтобы я получал только уникальные элементы из каждого массива в том же порядке, в котором они были вставлены в исходные массивы?

1143
18 окт. '09 в 11:34
источник поделиться
73 ответов
  • 1
  • 2
  • 3

Чтобы просто объединить массивы (без удаления дубликатов)

Версия Array.concat использует Array.concat:

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

var array3 = array1.concat(array2); // Merges both arrays
// [ 'Vijendra', 'Singh', 'Singh', 'Shakya' ]

Версия 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.prototype и 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;
    }
});
1418
18 окт. '09 в 11:42
источник

Связанные вопросы


Похожие вопросы

С помощью Underscore.js или Lo-Dash вы можете:

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

http://underscorejs.org/#union

http://lodash.com/docs#union

543
08 мая '12 в 16:24
источник

Сначала соедините два массива, затем отфильтруйте только уникальные элементы.

var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b);
var d = c.filter(function (item, pos) {return c.indexOf(item) == pos});

// d is [1,2,3,101,10]

http://jsfiddle.net/simo/98622/

Изменить

Как было предложено @Dmitry (см. второй комментарий ниже), более эффективное решение будет состоять в том, чтобы отфильтровать уникальные элементы в b перед конкатенацией с помощью a

var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b.filter(function (item) {
    return a.indexOf(item) < 0;
}));

// d is [1,2,3,101,10]
223
15 апр. '14 в 13:08
источник

Это решение ECMAScript 6, используя оператор распространения и обобщенные массивы.

В настоящее время он работает только с Firefox и, возможно, Internet Explorer Technical Preview.

Но если вы используете Babel, вы можете получить его сейчас.

// Input: [ [1, 2, 3], [101, 2, 1, 10], [2, 1] ]
// Output: [1, 2, 3, 101, 10]
function mergeDedupe(arr)
{
  return [...new Set([].concat(...arr))];
}
146
27 дек. '14 в 9:28
источник

ES6

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

ИЛИ

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

ИЛИ

[...new Set([...array1 ,...array2])]; //   => remove duplication
121
14 авг. '16 в 11:08
источник

Используя Set (ECMAScript 2015), это будет так просто:

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = Array.from(new Set(array1.concat(array2)));
47
06 янв. '18 в 22:05
источник

Вот немного другой взгляд на петлю. С некоторыми из оптимизаций в последней версии Chrome, это самый быстрый метод для разрешения объединения двух массивов (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: ~ 589 тыс. операций в секунду
фильтр: ~ 445 тыс. операций в секунду
lodash: 308 тыс. операций в секунду
для петель: 225 тыс. операций в секунду

В комментарии указывалось, что одна из моих переменных установки заставляла мой цикл опережать все остальные, потому что не нужно было инициализировать пустой массив для записи. Я согласен с этим, поэтому я переписал тест даже на игровое поле и включил еще более быстрый вариант.

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;
};

В этом альтернативном решении я объединил решение с одним ассоциативным массивом ответов, чтобы исключить .indexOf() в цикле, который значительно замедлял работу со вторым циклом, и включил некоторые другие оптимизации, которые другие пользователи предложили в их ответы также.

Верхний ответ здесь с двойной петлей для каждого значения (i-1) все еще значительно медленнее. У lodash все еще хорошо, и я бы порекомендовал его всем, кто не против добавить библиотеку в свой проект. Для тех, кто не хочет этого, мой цикл while все еще является хорошим ответом, и ответ фильтра очень ярко демонстрирует здесь, опередив все мои тесты последней версией Canary Chrome (44.0.2360) на момент написания этой статьи.

Посмотрите ответ Майка и Дана Стокера, если вы хотите ускорить процесс. Это, безусловно, самый быстрый из всех результатов после прохождения почти всех жизнеспособных ответов.

33
04 авг. '14 в 17:14
источник

Вы можете сделать это просто с помощью ECMAScript 6,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Используйте оператор распространения для конкатенации массива.
  • Используйте Set для создания отдельного набора элементов.
  • Снова используйте оператор смены, чтобы преобразовать Set в массив.
31
07 апр. '16 в 10:26
источник

объединить два массива и удалить дубликат в es6

let arr1 = [3, 5, 2, 2, 5, 5];
let arr2 = [2, 1, 66, 5];
let unique = [...new Set([...arr1,...arr2])];
console.log(unique);
// [ 3, 5, 2, 1, 66 ]
18
15 сент. '17 в 9:18
источник
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;
};

Значительно лучшая функция слияния массива.

16
19 авг. '11 в 16:34
источник

Просто избегайте вложенных циклов (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);
}
14
20 февр. '15 в 17:55
источник

Просто бросаю мои два цента.

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;
}

Это метод, который я использую много, он использует объект в качестве таблицы hashlookup для повторной проверки. Предполагая, что хэш равен O (1), то это выполняется в O (n), где n равно длине + b.length. Я честно понятия не имею, как браузер делает хэш, но он хорошо работает на многих тысячах точек данных.

14
12 дек. '12 в 22:50
источник

Почему вы не используете объект? Похоже, вы пытаетесь смоделировать набор. Однако это не будет сохранять порядок.

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
}
13
18 окт. '09 в 11:51
источник

ES6 решение для объединения

let arr1 = [1,2,3,4,5];
let arr2 = [3,4,5,6];
let result = [...new Set([...arr1, ...arr2])];
console.log(result);
9
13 февр. '19 в 21:15
источник

Упрощенный simo answer и превратил его в приятную функцию.

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}
8
09 июня '17 в 20:56
источник

Мои полторы пенни:

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);
8
12 окт. '15 в 18:53
источник

Лучшее решение...

Вы можете проверить прямо в консоли браузера, нажав...

Без дубликата

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"]
8
22 марта '16 в 8:17
источник

Вы можете достичь этого просто используя Underscore.js = > uniq:

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

console.log(array3)

Он напечатает [ "Vijendra", "Singh", "Shakya" ].

7
18 апр. '17 в 15:47
источник
//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

6
18 окт. '09 в 11:43
источник

Это можно сделать с помощью 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
29 марта '18 в 22:06
источник

Новое решение (которое использует 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;
  };
5
18 окт. '09 в 11:42
источник
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 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
26 июля '13 в 14:38
источник
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

Хорошая вещь об этом - производительность и что вы в целом при работе с массивами - это цепочки, такие как фильтр, карта и т.д., Чтобы вы могли добавить эту строку, и она будет конкатцировать и дедуплицировать массив2 с помощью массива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, и это был бы единственный способ уважения к цепочке - определение новой функции нарушит ее, поэтому я думаю, что это как единственный способ добиться этого)

5
08 июня '18 в 6:38
источник
  • Современный способ достижения этого - просто использовать оператор распространения.
  • И чтобы избежать дублирования, мы можем эффективно использовать наборы; Наборы не допускают дублирования по умолчанию.
  • Чтобы получить вывод как массив обратно из Set, мы можем использовать Array.from()

Итак, вот демонстрация для вашего сценария -

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var resArr = Array.from(new Set([...array1, ...array2]));
console.log(resArr);
4
15 февр. '19 в 17:07
источник

Для ES6 всего одна строка:

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]
4
22 сент. '18 в 12:10
источник
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
25 сент. '18 в 11:54
источник

ради этого... вот однолинейное решение:

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

Не особенно читаемый, но он может помочь кому-то:

  1. Применяет функцию уменьшения с исходным значением аккумулятора, установленным в пустой массив.
  2. Функция уменьшения использует concat для добавления каждого подматрица в массив накопителей.
  3. Результат этого передается как параметр конструктора для создания нового Set.
  4. Оператор spread используется для преобразования Set в массив.
  5. Функция sort() применяется к новому массиву.
3
04 дек. '17 в 0:48
источник

DeDuplicate single или Merge и DeDuplicate для ввода нескольких массивов. Пример ниже.

использование ES6 - установка для деструктурирования

Я написал эту простую функцию, которая принимает несколько аргументов массива. В значительной степени то же, что и решение выше, просто имеет более практичный вариант использования. Эта функция не объединяет повторяющиеся значения в один массив только для того, чтобы удалить их на более позднем этапе.

ОПРЕДЕЛЕНИЕ КОРОТКИХ ФУНКЦИЙ (всего 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);
}

ИСПОЛЬЗУЙТЕ ПРИМЕР КОДЕПЕНА:

// 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]
2
05 июня '18 в 5:46
источник

Предполагая, что исходные массивы не нуждаются в дедупликации, это должно быть довольно быстро, сохранить исходный порядок и не изменять исходные массивы...

function arrayMerge(base, addendum){
    var out = [].concat(base);
    for(var i=0,len=addendum.length;i<len;i++){
        if(base.indexOf(addendum[i])<0){
            out.push(addendum[i]);
        }
    }
    return out;
}

использование:

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

console.log(array3);
//-> [ 'Vijendra', 'Singh', 'Shakya' ]
2
09 февр. '16 в 2:27
источник

Самое простое решение с фильтром:

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

var mergedArrayWithoutDuplicates = array1.concat(
  array2.filter(seccondArrayItem => !array1.includes(seccondArrayItem))
);
2
07 марта '19 в 11:57
источник
  • 1
  • 2
  • 3

Посмотрите другие вопросы по меткам или Задайте вопрос