Javascript: эффективно сравнить два целых массива

У меня есть два целых массива, которые содержат числовые значения. Я хочу просмотреть оба списка и проверить наличие (или отсутствие) между списками. То есть Я хочу выполнить итерацию через массив и найти те элементы, которые отображаются в обоих списках, в то время как в отдельной функции я хочу пройти через массивы и найти элементы, которые находятся в первом, а не во втором.

Очевидный способ сделать это вложен для циклов:

var containedInFirst = false;
for (var primaryID = 0; primaryID < PrimaryArray.length; primaryID++) {
        containedInFirst = false;
        for (var secondaryID = 0; secondaryID < SecondaryArray.length; secondaryID++) {
            if (PrimaryArray [primaryID] === SecondaryArray[secondaryID]) {
                containedInFirst = true;
                break;
            }
        }

//Do some more stuff based on the value of containedInFirst here
}

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

Любые мысли о более эффективных или элегантных решениях?

Ответ 1

Отсортируйте их первым и проведите мимо них параллельно.

a.sort();
b.sort();

left = []; both = []; right = []; 
i = 0; j = 0;
while (i < a.length && j < b.length) {
    if (a[i] < b[j]) {
        left.push(a[i]);
        ++i;
    } else if (b[j] < a[i]) {
        right.push(b[j]);
        ++j;
    } else {
        both.push(a[i]);
        ++i; ++j;
    }
}
while (i < a.length) {
    left.push(a[i]);
    ++i;
}
while (j < b.length) {
    right.push(b[j]);
    ++j;
}

Ответ 2

Все слишком усложняют это. Здесь один вкладыш:

var isEqual = (JSON.stringify(arr1.sort()) === JSON.stringify(arr2.sort()));

Ответ 3

При использовании двух вложенных циклов сложность будет O (n * n). Сортировка обоих массивов может выполняться по сложности O (n log n).

AS Marcelo Cantos заявила, что утка-waddle:) через паралеллу имеет сложность O (n), что приводит к общей сложности O (n log n) + O (n), которая является O (n log n).

Ответ 4

Сортируйте оба массива, чем цикл, один раз и сравните:

function diff(arrayToCompareTo, comparedArray)
{
  Sort(arrayToCompareTo);
  Sort(comparedArray);

  var difference = [], same = [];
  for(var i = 0; i < arrayToCompareTo.length; ++i)
  {
     if (arrayToCompareTo[i] != comparedArray[i])
        difference.push(comparedArray[i]);
     else
        same.push(comparedArray[i]);
  }

  if (comparedArray.length > arrayToCompareTo.length)
     for(var i = arrayToCompareTo.length; i < comparedArray.length; ++i)
       difference.push(comparedArray[i]);
}

Это не проверено, поэтому, если что-то не так, пожалуйста, дайте мне знать.
В любом случае, это должно привести вас в правильное направление, так как оно O (N) в лучшем случае и O (M) в худшем случае, если comparedArray.length > arrayToCompareTo.length, оно намного более эффективно, чем O (N ^ 2). Обратите внимание, что сортировка принимает O (N log N).

Ответ 5

Я думаю, что у меня есть решение с эффективностью O (N) (нет необходимости), вот оно:

var firstNotSecond;
function CompareIntArrays(arr1, arr2)
{
    firstNotSecond = new Array();

    var arr3 = new Array(); //appear in both
    var arrTemp = new Array(); //used for firstNotSecond
    var usedNumbers = new Array();

    for (var i = 0; i < arr1.length; i++)
    {
        var key = arr1[i];
        usedNumbers[key] = true;
        arrTemp[key + ""] = true;
    }

    for (var i = 0; i < arr2.length; i++)
    {
        var key = arr2[i];
        if (usedNumbers[key])
        {
            arr3[arr3.length] = key;
            arrTemp[key] = false;
        }
    }

    for (var key in arrTemp)
        if (arrTemp[key])
            firstNotSecond[firstNotSecond.length] = parseInt(key);

    return arr3;
}

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

Этот код полагается на то, что оба массива содержат только целые числа.

Пример использования:

alert(CompareIntArrays([15, 551, 25, 910, 11], [25, 11, 785, 880, 15]));
alert(firstNotSecond);

Протестировано массивами, имеющими 100 000 наименований: менее одной секунды. Протестировано с массивами, имеющими 200 000 предметов каждый: менее 2 секунд.

Ответ 6

Другая возможность - это упорядочить эти массивы при их создании. Я не уверен, что вы можете это сделать. Но если это возможно, это немного увеличит добавление элемента в массив (O (log n) вместо O (1)), но это уменьшит сложность вашего алгоритма сравнения до O (n)