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

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

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

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

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

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

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

+1228
источник поделиться
75 ответов
  • 1
  • 2
  • 3

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

Версия 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.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;
    }
});
+1528
источник

С 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

+574
источник
другие ответы

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


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

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

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]

+242
источник

Это решение 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))];
}
+166
источник

ES6

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

ИЛИ

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

ИЛИ

[...new Set([...array1 ,...array2])]; //   => remove duplication
+148
источник

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

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = Array.from(new Set(array1.concat(array2)));
+56
источник

Вот немного другой взгляд на петлю. С некоторыми из оптимизаций в последней версии 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) на момент написания этой статьи.

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

+36
источник

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

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

объединить два массива и удалить дубликат в 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 ]
+21
источник

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

let arr1 = [1,2,3,4,5];
let arr2 = [3,4,5,6];
let result = [...new Set([...arr1, ...arr2])];
console.log(result);
+20
источник
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;
};

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

+18
источник

Просто избегайте вложенных циклов (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);
}
+18
источник

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

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. Я честно понятия не имею, как браузер делает хэш, но он хорошо работает на многих тысячах точек данных.

+16
источник

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

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
}
+14
источник

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

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

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

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"]
+11
источник
  • Современный способ достижения этого - просто использовать оператор распространения.
  • И чтобы избежать дублирования, мы можем эффективно использовать наборы; Наборы не допускают дублирования по умолчанию.
  • Чтобы получить вывод как массив обратно из Set, мы можем использовать Array.from()

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

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var resArr = Array.from(new Set([...array1, ...array2]));
console.log(resArr);
+11
источник

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

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}
+10
источник

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

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);
+9
источник

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

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

console.log(array3)

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

+8
источник

Новое решение (которое использует 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;
  };
+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

+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
источник

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

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]
+6
источник
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
источник
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
источник

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

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
источник

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]
+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 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var mergedArrayWithoutDuplicates = array1.concat(
  array2.filter(seccondArrayItem => !array1.includes(seccondArrayItem))
);
+3
источник

В Dojo 1,6 +

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

dojo.forEach(array3, function(item) {
    if (dojo.indexOf(unique, item) > -1) return;
    unique.push(item); 
});

Обновление

См. рабочий код.

http://jsfiddle.net/UAxJa/1/

+2
источник
  • 1
  • 2
  • 3

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