Как избежать вложенных циклов в реальном тесте кодирования Javascript

Между двумя входными массивами найдите один и тот же массив или массивы и верните их.

Я просто мог придумать решение для вложенного цикла.


const compareArrs = (arr1, arr2) => {
  const rtnArr = []
  for (let ar1 of arr1){
    for (let ar2 of arr2){
      if (JSON.stringify(ar1) === JSON.stringify(ar2)){
        rtnArr.push(ar1)
      }
    }
  }
  return rtnArr
}

// compare [1, 2] [3, 4] with [1, 2]
console.info(compareArrs([[1, 2], [3, 4]], [[1, 2]]))

[[1, 2]] должно быть возвращено.

Я не думаю, что за этот вопрос следует проголосовать, поскольку он задает вопрос о том, как сделать вышеизложенное лучше.

Christopher Grigg 28.05.2021 08:51
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
189
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Сопоставьте каждый подмассив одного аргумента и поместите его в набор. С другим аргументом выполните итерацию по нему, составляя строки по мере продвижения, и найдите элемент, для которого строковый массив уже находится в наборе, для общей сложности O(N):

const compareArrs = (arr1, arr2) => {
  const arr1StringifiedSet = new Set(arr1.map(JSON.stringify));
  return arr2.find(
    subarr2 => arr1StringifiedSet.has(JSON.stringify(subarr2))
  );
};

console.info(compareArrs([[1, 2], [3, 4]], [[1, 2]]));

(Для сравнения, вложенный цикл имеет сложность O(N^2))

Как отмечается в комментариях, если вам действительно нужны совпадающие массивы все, а не только первый, используйте .filter вместо .find:

const compareArrs = (arr1, arr2) => {
  const arr1StringifiedSet = new Set(arr1.map(JSON.stringify));
  return arr2.filter(
    subarr2 => arr1StringifiedSet.has(JSON.stringify(subarr2))
  );
};

console.info(compareArrs([[1, 2], [3, 4]], [[1, 2]]));

Я считаю, что второй аргумент может иметь более одного элемента, иначе для него нет смысла быть массивом. В этом случае вы можете использовать filter() вместо find().

Shidersz 28.05.2019 05:40

Вопрос говорит find the same array and return them., поэтому я понял, что это означает, что будет соответствующий элемент один. Конечно, если он хочет найти совпадающие массивы все, используйте вместо этого filter

CertainPerformance 28.05.2019 05:41

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

Shidersz 28.05.2019 06:06

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

Ryan Kim 28.05.2019 06:49

@JinYongKim Похоже, ваш ожидаемый результат на самом деле [[1, 2]], а не [1, 2], если вы хотите, чтобы результатом был массив всех совпадающих массивов?

CertainPerformance 28.05.2019 06:50

Да, вы правы, я снова отредактировал свой вопрос. Спасибо, что дал мне знать.

Ryan Kim 29.05.2019 10:30

Вы можете имитировать набор массивов с вложенными картами, где [1, 2] становится записью в корневой карте, где ключ равен 1, а значение — другая карта с ключом 2, например:

const present = Symbol('present');

class ArraySet {
    constructor() {
        this._root = new Map();
    }

    add(array) {
        let node = this._root;

        for (const item of array) {
            if (node.has(item)) {
                node = node.get(item);
            } else {
                node.set(item, node = new Map());
            }
        }

        node[present] = true;
    }

    has(array) {
        let node = this._root;

        for (const item of array) {
            node = node.get(item);

            if (node === undefined) {
                return false;
            }
        }

        return !!node[present];
    }
}

тогда:

const compareArrs = (arr1, arr2) => {
    const set = new ArraySet();
    arr1.forEach(set.add, set);
    return arr2.filter(set.has, set);
};

const present = Symbol('present');

class ArraySet {
    constructor() {
        this._root = new Map();
    }

    add(array) {
        let node = this._root;

        for (const item of array) {
            if (node.has(item)) {
                node = node.get(item);
            } else {
                node.set(item, node = new Map());
            }
        }

        node[present] = true;
    }

    has(array) {
        let node = this._root;

        for (const item of array) {
            node = node.get(item);

            if (node === undefined) {
                return false;
            }
        }

        return !!node[present];
    }
}

const compareArrs = (arr1, arr2) => {
    const set = new ArraySet();
    arr1.forEach(set.add, set);
    return arr2.filter(set.has, set);
};

console.info(compareArrs([[1, 2], [3, 4]], [[1, 2]]));

Это занимает время, пропорциональное arr1.concat(arr2).flat().length. Другой подход, который работает до тех пор, пока вы можете создать соответствующую функцию сравнения для массивов, например эту лексикографическую, когда обычные операторы JavaScript дают общий порядок:

const lexCompare = (a, b) => {
    const len = Math.min(a.length, b.length);

    for (let i = 0; i < len; i++) {
        if (a[i] < b[i]) return -1;
        if (a[i] > b[i]) return 1;
    }

    return a.length - b.length;
};

и входные массивы не содержат дубликатов должен сначала отсортировать комбинацию обоих массивов:

const sorted = arr1.concat(arr2).sort(lexCompare);

затем найдите дубликаты, созданные слиянием, рядом друг с другом:

return sorted.filter((item, i) => {
    if (i === 0) return false;

    const prev = sorted[i - 1];
    return prev.length === item.length && prev.every((x, i) => x === item[i]);
});

за время O((|arr1| + |arr2|) log (|arr1| + |arr2|) l), где l — максимальная длина массива. Вы можете сократить этот (|arr1| + |arr2|) журнал (|arr1| + |arr2|) до |arr1| журнал |обр1| + |обр2| журнал |обр2| но это может оказаться медленнее.

Вы можете использовать Массив.прототип.уменьшить() в сочетании с Массив.прототип.найти() и Массив.прототип.push().

const compareArrs = (arr1, arr2) => arr1.reduce((a, c) => {
  const found = arr2.find(arr => JSON.stringify(arr) === JSON.stringify(c))
  if (found.length) a.push(found)
  return a
}, [])

// compare [1, 2] [3, 4] with [1, 2]
console.info(compareArrs([[1, 2]], [[1, 2], [3, 4]]))

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

Ry- 28.05.2019 05:46

@Ry- Вы правы, я улучшил свой ответ, используя Array#concat().. Спасибо за комментарий.

Yosvel Quintero Arguelles 28.05.2019 05:52
[].concat это тоже самое. Вам нужно использовать push.
Ry- 28.05.2019 05:55

@Ry- Обновленный ответ, большое спасибо за комментарии

Yosvel Quintero Arguelles 28.05.2019 06:00

Другие вопросы по теме