Простейший код для пересечения массива в javascript

Какой самый простой, бесплатный для библиотеки код для реализации пересечений массивов в javascript? Я хочу написать

intersection([1,2,3], [2,3,4,5])

и получим

[2, 3]

Ответ 1

Используйте комбинацию Array.prototype.filter и Array.prototype.indexOf:

array1.filter(value => -1 !== array2.indexOf(value))

Или, как предложил vrugtehagel в комментариях, вы можете использовать более свежий Array.prototype.includes для еще более простого кода:

array1.filter(value => array2.includes(value))

Для старых браузеров:

array1.filter(function(n) {
    return array2.indexOf(n) !== -1;
});

Ответ 2

Разрушительный кажется простейшим, особенно если мы можем предположить, что вход сортируется:

/* destructively finds the intersection of 
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *  State of input arrays is undefined when
 *  the function returns.  They should be 
 *  (prolly) be dumped.
 *
 *  Should have O(n) operations, where n is 
 *    n = MIN(a.length, b.length)
 */
function intersection_destructive(a, b)
{
  var result = [];
  while( a.length > 0 && b.length > 0 )
  {  
     if      (a[0] < b[0] ){ a.shift(); }
     else if (a[0] > b[0] ){ b.shift(); }
     else /* they're equal */
     {
       result.push(a.shift());
       b.shift();
     }
  }

  return result;
}

Неразрушающий процесс должен быть более сложным, поскольку нам нужно отслеживать показатели:

/* finds the intersection of 
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *
 *  Should have O(n) operations, where n is 
 *    n = MIN(a.length(), b.length())
 */
function intersect_safe(a, b)
{
  var ai=0, bi=0;
  var result = [];

  while( ai < a.length && bi < b.length )
  {
     if      (a[ai] < b[bi] ){ ai++; }
     else if (a[ai] > b[bi] ){ bi++; }
     else /* they're equal */
     {
       result.push(a[ai]);
       ai++;
       bi++;
     }
  }

  return result;
}

Ответ 3

Если ваша среда поддерживает набор ECMAScript 6, один простой и предположительно эффективный (см. Ссылку на спецификацию) способ:

function intersect(a, b) {
  var setA = new Set(a);
  var setB = new Set(b);
  var intersection = new Set([...setA].filter(x => setB.has(x)));
  return Array.from(intersection);
}

Короче, но менее читабельно (также без создания дополнительного Set пересечений):

function intersect(a, b) {
      return [...new Set(a)].filter(x => new Set(b).has(x));
}

Как избежать нового Set от b каждый раз:

function intersect(a, b) {
      var setB = new Set(b);
      return [...new Set(a)].filter(x => setB.has(x));
}

Обратите внимание, что при использовании множеств вы получите только различные значения, поэтому new Set[1,2,3,3].size оценивается как 3.

Ответ 4

Использование Underscore.js или lodash.js

_.intersection( [0,345,324] , [1,0,324] )  // gives [0,324]

Ответ 5

Мой вклад в условия ES6. В общем случае он находит пересечение массива с неопределенным числом массивов, предоставленным в качестве аргументов.

Array.prototype.intersect = function(...a) {
  return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
     arr = [0,1,2,3,4,5,6,7,8,9];

document.write("<pre>" + JSON.stringify(arr.intersect(...arrs)) + "</pre>");

Ответ 6

Как просто использовать ассоциативные массивы?

function intersect(a, b) {
    var d1 = {};
    var d2 = {};
    var results = [];
    for (var i = 0; i < a.length; i++) {
        d1[a[i]] = true;
    }
    for (var j = 0; j < b.length; j++) {
        d2[b[j]] = true;
    }
    for (var k in d1) {
        if (d2[k]) 
            results.push(k);
    }
    return results;
}

изменить:

// new version
function intersect(a, b) {
    var d = {};
    var results = [];
    for (var i = 0; i < b.length; i++) {
        d[b[i]] = true;
    }
    for (var j = 0; j < a.length; j++) {
        if (d[a[j]]) 
            results.push(a[j]);
    }
    return results;
}

Ответ 7

Производительность реализации @atk для отсортированных массивов примитивов может быть улучшена с помощью .pop, а не .shift.

function intersect(array1, array2) {
   var result = [];
   // Don't destroy the original arrays
   var a = array1.slice(0);
   var b = array2.slice(0);
   var aLast = a.length - 1;
   var bLast = b.length - 1;
   while (aLast >= 0 && bLast >= 0) {
      if (a[aLast] > b[bLast] ) {
         a.pop();
         aLast--;
      } else if (a[aLast] < b[bLast] ){
         b.pop();
         bLast--;
      } else /* they're equal */ {
         result.push(a.pop());
         b.pop();
         aLast--;
         bLast--;
      }
   }
   return result;
}

Я создал тест с использованием jsPerf: http://bit.ly/P9FrZK. Это примерно в три раза быстрее использовать .pop.

Ответ 8

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

var a = [1,2,3];
var b = [2,3,4,5];
var c = $(b).not($(b).not(a));
alert(c);

Ответ 9

// Return elements of array a that are also in b in linear time:
function intersect(a, b) {
  return a.filter(Set.prototype.has, new Set(b));
}

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

Ответ 10

  • Сортировка
  • проверьте один за другим из индекса 0, создайте из него новый массив.

Что-то вроде этого, Не проверено хорошо, хотя.

function intersection(x,y){
 x.sort();y.sort();
 var i=j=0;ret=[];
 while(i<x.length && j<y.length){
  if(x[i]<y[j])i++;
  else if(y[j]<x[i])j++;
  else {
   ret.push(x[i]);
   i++,j++;
  }
 }
 return ret;
}

alert(intersection([1,2,3], [2,3,4,5]));

PS: Алгоритм, предназначенный только для чисел и нормальных строк, пересечение арбинных массивов объектов может не работать.

Ответ 11

Для массивов, содержащих только строки или числа, вы можете сделать что-то с сортировкой, как и некоторые другие ответы. Для общего случая массивов произвольных объектов я не думаю, что вы можете избежать длительного пути. Следующее даст вам пересечение любого количества массивов, предоставленных в качестве параметров, для arrayIntersection:

var arrayContains = Array.prototype.indexOf ?
    function(arr, val) {
        return arr.indexOf(val) > -1;
    } :
    function(arr, val) {
        var i = arr.length;
        while (i--) {
            if (arr[i] === val) {
                return true;
            }
        }
        return false;
    };

function arrayIntersection() {
    var val, arrayCount, firstArray, i, j, intersection = [], missing;
    var arrays = Array.prototype.slice.call(arguments); // Convert arguments into a real array

    // Search for common values
    firstArray = arrays.pop();
    if (firstArray) {
        j = firstArray.length;
        arrayCount = arrays.length;
        while (j--) {
            val = firstArray[j];
            missing = false;

            // Check val is present in each remaining array 
            i = arrayCount;
            while (!missing && i--) {
                if ( !arrayContains(arrays[i], val) ) {
                    missing = true;
                }
            }
            if (!missing) {
                intersection.push(val);
            }
        }
    }
    return intersection;
}

arrayIntersection( [1, 2, 3, "a"], [1, "a", 2], ["a", 1] ); // Gives [1, "a"]; 

Ответ 12

Он довольно короткий, используя ES2015 и Sets. Принимает значения типа Array, такие как String, и удаляет дубликаты.

let intersection = function(a, b) {
  a = new Set(a), b = new Set(b);
  return [...a].filter(v => b.has(v));
};

console.log(intersection([1,2,1,2,3], [2,3,5,4,5,3]));

console.log(intersection('ccaabbab', 'addb').join(''));

Ответ 13

Другой индексированный подход, способный обрабатывать сразу любое количество массивов:

// Calculate intersection of multiple array or object values.
function intersect (arrList) {
    var arrLength = Object.keys(arrList).length;
        // (Also accepts regular objects as input)
    var index = {};
    for (var i in arrList) {
        for (var j in arrList[i]) {
            var v = arrList[i][j];
            if (index[v] === undefined) index[v] = 0;
            index[v]++;
        };
    };
    var retv = [];
    for (var i in index) {
        if (index[i] == arrLength) retv.push(i);
    };
    return retv;
};

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

intersect ([arr1, arr2, arr3...]);

... но он прозрачно принимает объекты как параметр или как любой из элементов, подлежащих пересечению (всегда возвращающий массив общих значений). Примеры:

intersect ({foo: [1, 2, 3, 4], bar: {a: 2, j:4}}); // [2, 4]
intersect ([{x: "hello", y: "world"}, ["hello", "user"]]); // ["hello"]

РЕДАКТИРОВАТЬ: Я только заметил, что это, в некотором смысле, немного глючит.

То есть: я закодировал его, думая, что массивы ввода не могут содержать повторений (как не показано в примере).

Но если входные массивы состоят из повторений, это приведет к неправильным результатам. Пример (с использованием нижеприведенной реализации):

intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]);
// Expected: [ '1' ]
// Actual: [ '1', '3' ]

К счастью, это легко исправить, просто добавив индексирование второго уровня. То есть:

Изменить:

        if (index[v] === undefined) index[v] = 0;
        index[v]++;

по:

        if (index[v] === undefined) index[v] = {};
        index[v][i] = true; // Mark as present in i input.

... и:

         if (index[i] == arrLength) retv.push(i);

по:

         if (Object.keys(index[i]).length == arrLength) retv.push(i);

Полный пример:

// Calculate intersection of multiple array or object values.
function intersect (arrList) {
    var arrLength = Object.keys(arrList).length;
        // (Also accepts regular objects as input)
    var index = {};
    for (var i in arrList) {
        for (var j in arrList[i]) {
            var v = arrList[i][j];
            if (index[v] === undefined) index[v] = {};
            index[v][i] = true; // Mark as present in i input.
        };
    };
    var retv = [];
    for (var i in index) {
        if (Object.keys(index[i]).length == arrLength) retv.push(i);
    };
    return retv;
};

intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]); // [ '1' ]

Ответ 14

Небольшая настройка для самого маленького здесь (filter/indexOf solution), а именно создание индекса значений в одном из массивов с использованием объекта JavaScript, уменьшит его от O (N * M) до "вероятно" линейного времени. source1 source2

function intersect(a, b) {
  var aa = {};
  a.forEach(function(v) { aa[v]=1; });
  return b.filter(function(v) { return v in aa; });
}

Это не самое простое решение (это больше кода, чем filter + indexOf), и оно не является самым быстрым (возможно, медленнее на постоянный коэффициент, чем intersect_safe()), но кажется довольно хорошим балансом. Он находится на очень простой стороне, обеспечивая при этом хорошую производительность и не требует предварительно отсортированных входов.

Ответ 15

function intersection(A,B){
var result = new Array();
for (i=0; i<A.length; i++) {
    for (j=0; j<B.length; j++) {
        if (A[i] == B[j] && $.inArray(A[i],result) == -1) {
            result.push(A[i]);
        }
    }
}
return result;
}

Ответ 16

С некоторыми ограничениями на ваши данные вы можете сделать это в линейном времени!

Для положительных целых чисел: используйте массив, сопоставляющий значения с "видимыми/не замеченными" логическими.

function intersectIntegers(array1,array2) { 
   var seen=[],
       result=[];
   for (var i = 0; i < array1.length; i++) {
     seen[array1[i]] = true;
   }
   for (var i = 0; i < array2.length; i++) {
     if ( seen[array2[i]])
        result.push(array2[i]);
   }
   return result;
}

Существует аналогичный метод для объектов: возьмите фиктивный ключ, установите его для "true" для каждого элемента в массиве 1, затем найдите этот ключ в элементах array2. Очистите, когда закончите.

function intersectObjects(array1,array2) { 
   var result=[];
   var key="tmpKey_intersect"
   for (var i = 0; i < array1.length; i++) {
     array1[i][key] = true;
   }
   for (var i = 0; i < array2.length; i++) {
     if (array2[i][key])
        result.push(array2[i]);
   }
   for (var i = 0; i < array1.length; i++) {
     delete array1[i][key];
   }
   return result;
}

Конечно, вы должны быть уверены, что ключ не появился раньше, иначе вы будете уничтожать свои данные...

Ответ 17

Я буду способствовать тому, что было лучше для меня:

if (!Array.prototype.intersect){
Array.prototype.intersect = function (arr1) {

    var r = [], o = {}, l = this.length, i, v;
    for (i = 0; i < l; i++) {
        o[this[i]] = true;
    }
    l = arr1.length;
    for (i = 0; i < l; i++) {
        v = arr1[i];
        if (v in o) {
            r.push(v);
        }
    }
    return r;
};
}

Ответ 18

"indexOf" для IE 9.0, chrome, firefox, opera,

    function intersection(a,b){
     var rs = [], x = a.length;
     while (x--) b.indexOf(a[x])!=-1 && rs.push(a[x]);
     return rs.sort();
    }

intersection([1,2,3], [2,3,4,5]);
//Result:  [2,3]

Ответ 19

Это, наверное, самый простой, кроме list1.filter(n = > list2.includes(n))

var list1 = ['bread', 'ice cream', 'cereals', 'strawberry', 'chocolate']
var list2 = ['bread', 'cherry', 'ice cream', 'oats']

function check_common(list1, list2){
	
	list3 = []
	for (let i=0; i<list1.length; i++){
		
		for (let j=0; j<list2.length; j++){	
			if (list1[i] === list2[j]){
				list3.push(list1[i]);				
			}		
		}
		
	}
	return list3
	
}

check_common(list1, list2) // ["bread", "ice cream"]

Ответ 20

'use strict'

// Example 1
function intersection(a1, a2) {
    return a1.filter(x => a2.indexOf(x) > -1)
}

// Example 2 (prototype function)
Array.prototype.intersection = function(arr) {
    return this.filter(x => arr.indexOf(x) > -1)
} 

const a1 = [1, 2, 3]
const a2 = [2, 3, 4, 5]

console.log(intersection(a1, a2))
console.log(a1.intersection(a2))

Ответ 21

Функциональный подход с ES2015

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

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

// small, reusable auxiliary functions

const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
const apply = f => x => f(x);


// intersection

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


// mock data

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


// run it

console.log( intersect(xs) (ys) );

Ответ 22

Для простоты:

// Usage
const intersection = allLists
  .reduce(intersect, allValues)
  .reduce(removeDuplicates, []);


// Implementation
const intersect = (intersection, list) =>
  intersection.filter(item =>
    list.some(x => x === item));

const removeDuplicates = (uniques, item) =>
  uniques.includes(item) ? uniques : uniques.concat(item);


// Example Data
const somePeople = [bob, doug, jill];
const otherPeople = [sarah, bob, jill];
const morePeople = [jack, jill];

const allPeople = [...somePeople, ...otherPeople, ...morePeople];
const allGroups = [somePeople, otherPeople, morePeople];

// Example Usage
const intersection = allGroups
  .reduce(intersect, allPeople)
  .reduce(removeDuplicates, []);

intersection; // [jill]

Преимущества:

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

Недостатки:

  • использование более высокой памяти
  • более высокая загрузка процессора
  • требует понимания сокращения
  • требует понимания потока данных

Вы бы не захотели использовать это для работы с 3D-движком или ядром, но если у вас возникли проблемы с его запуском в приложении, основанном на событиях, ваш дизайн будет иметь большие проблемы.

Ответ 23

.reduce, чтобы построить карту, и .filter, чтобы найти пересечение. delete в пределах .filter позволяет нам рассматривать второй массив, как если бы он был уникальным.

function intersection (a, b) {
  var seen = a.reduce(function (h, k) {
    h[k] = true;
    return h;
  }, {});

  return b.filter(function (k) {
    var exists = seen[k];
    delete seen[k];
    return exists;
  });
}

Я считаю, что этот подход довольно легко рассуждать. Он работает в постоянное время.

Ответ 24

Вот underscore.js реализация:

_.intersection = function(array) {
  if (array == null) return [];
  var result = [];
  var argsLength = arguments.length;
  for (var i = 0, length = array.length; i < length; i++) {
    var item = array[i];
    if (_.contains(result, item)) continue;
    for (var j = 1; j < argsLength; j++) {
      if (!_.contains(arguments[j], item)) break;
    }
    if (j === argsLength) result.push(item);
  }
  return result;
};

Источник: http://underscorejs.org/docs/underscore.html#section-62

Ответ 25

var listA = [1,2,3,4,5,6,7];
var listB = [2,4,6,8];

var result = listA.filter(itemA=> {
    return listB.some(itemB => itemB === itemA);
});

Ответ 26

function getIntersection(arr1, arr2){
    var result = [];
    arr1.forEach(function(elem){
        arr2.forEach(function(elem2){
            if(elem === elem2){
                result.push(elem);
            }
        });
    });
    return result;
}

getIntersection([1,2,3], [2,3,4,5]); // [ 2, 3 ]

Ответ 27

Если вам нужно обработать его, пересекая несколько массивов:

  const intersect = (a, b,... rest) = > {
 if (rest.length === 0) return [... new Set (a)]. filter (x = > new Set (b).has(x));
 return пересекаются (a, пересекаются (b,... rest));
};

console.log(пересекаются ([1,2,3,4,5], [1,2], [1, 2, 3,4,5], [2, 10, 1]))//[1, 2]код>

Ответ 28

Стиль ES6 простой способ.

const intersection = (a, b) => {
  const s = new Set(b);
  return a.filter(x => s.has(x));
};

Пример:

intersection([1, 2, 3], [4, 3, 2]); // [2, 3]

Ответ 29

Вместо использования indexOf вы также можете использовать Array.protype.include.

function intersection(arr1, arr2) {
  return arr1.filter((ele => {
    return arr2.includes(ele);
  }));
}

console.log(intersection([1,2,3], [2,3,4,5]));

Ответ 30

Если вы хотите использовать принятый ответ, но нуждаетесь в поддержке Internet Explorer, вам следует избегать краткой аннотации функции стрелки. Вот отредактированный однострочный текст, который будет работать и в IE:

// accepted aswer: array1.filter(value => -1 !== array2.indexOf(value));
// IE-supported syntax:
array1.filter(function(value) { return -1 !== array2.indexOf(value) });