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

Ни один из вышеперечисленных ответов не является удовлетворительным IMO, поэтому я использую следующее:

// Cross-browser AddEventListener
function ael(e, n, h){
    if( e.addEventListener ){
        e.addEventListener(n, h, true);
    }else{
        e.attachEvent('on'+n, h);
    }
}

var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW

if(touch){
    ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
    ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}

// local mouse X,Y position in element
function showLocalPos(e){
    document.title = (mx - e.getBoundingClientRect().left)
        + 'x'
        + Math.round(my - e.getBoundingClientRect().top);
}

И если вам когда-либо понадобится знать текущую позицию прокрутки Y страницы:

var yscroll = window.pageYOffset
        || (document.documentElement && document.documentElement.scrollTop)
        || document.body.scrollTop; // scroll Y position in page
485
задан Ricardo 7 December 2013 в 04:40
поделиться

9 ответов

Используйте комбинацию 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;
});
947
ответ дан 22 November 2019 в 22:27
поделиться

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

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

const intersection = (a, b) => {
  b = new Set(b); // recycling variable
  return [...new Set(a)].filter(e => b.has(e));
};

console.log(intersection([1, 2, 3, 1, 1], [1, 2, 4])); // Array [ 1, 2 ]
0
ответ дан Grant Miller 7 December 2013 в 04:40
поделиться

Мой вклад в терминах 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>");
13
ответ дан Redu 7 December 2013 в 04:40
поделиться

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

// 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-движок или ядро ​​работают, но если у вас есть проблемы с его запуском в приложении, основанном на событиях, у вашего дизайна большие проблемы.

2
ответ дан Norguard 7 December 2013 в 04:40
поделиться
  1. Сортировать
  2. проверять по одному из индекс 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: Алгоритм, предназначенный только для чисел и нормальных строк, пересечение произвольных массивов объектов может не работать.

8
ответ дан 22 November 2019 в 22:27
поделиться

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

/* 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;
}
155
ответ дан 22 November 2019 в 22:27
поделиться

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

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;
}
12
ответ дан 22 November 2019 в 22:27
поделиться

Для массивов, содержащих только строки или числа, вы можете что-то сделать с сортировкой, как и в некоторых других ответах. В общем случае массивов произвольных объектов я не думаю, что вы сможете избежать этого долгим путем. Следующее даст вам пересечение любого количества массивов, предоставленных в качестве параметров для 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"]; 
7
ответ дан 22 November 2019 в 22:27
поделиться

"filter" и "indexOf" не поддерживаются в массиве в IE. Как насчет этого:

var array1 = [1, 2, 3];
var array2 = [2, 3, 4, 5];

var intersection = [];
for (i in array1) {
    for (j in array2) {
        if (array1[i] == array2[j]) intersection.push(array1[i]);
    }
}
-4
ответ дан 22 November 2019 в 22:27
поделиться
Другие вопросы по тегам:

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