15

Слияние/выпрямление массива массивов

11

У меня есть массив в JavaScript следующего вида:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

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

["$6", "$12", "$25", ...]

Какое решение наиболее эффективно для достижения этой цели?

5 ответ(ов)

6

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

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

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

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

Эта функция работает следующим образом: она использует метод reduce, который проходится по каждому элементу массива, проверяет, является ли элемент массивом с помощью Array.isArray(), и если это так, рекурсивно вызывает саму себя, чтобы "развернуть" вложенный массив. Если элемент не массив, он добавляется в результирующий массив. Таким образом, на выходе мы получаем одномерный массив, содержащий все элементы из исходного многомерного.

3

В вашем случае, вы можете использовать метод concat, который позволяет создать новый массив, не изменяя оригинальный. Для этого вы можете применить метод apply к Array.prototype.concat, чтобы развернуть вложенные массивы.

Вот пример кода:

var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 4 ]

Здесь oldArray - это массив массивов, а Array.prototype.concat.apply([], oldArray) создает новый массив, объединяя элементы без изменения oldArray. Использование apply позволяет передать oldArray как аргументы в concat, что приводит к «распаковке» элементов внутренних массивов.

0

Большинство ответов здесь не работают на огромных (например, 200 000 элементов) массивах, и даже если они и работают, то действуют медленно.

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

const flatten = function(arr, result = []) {
  for (let i = 0, length = arr.length; i < length; i++) {
    const value = arr[i];
    if (Array.isArray(value)) {
      flatten(value, result);
    } else {
      result.push(value);
    }
  }
  return result;
};

Примеры

Огромные массивы

flatten(Array(200000).fill([1]));

Данный код прекрасно справляется с огромными массивами. На моем компьютере выполнение этого кода занимает около 14 мс.

Вложенные массивы

flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));

Он работает и с вложенными массивами. Этот код возвращает [1, 1, 1, 1, 1, 1, 1, 1].

Массивы с разными уровнями вложенности

flatten([1, [1], [[1]]]);

У него нет никаких проблем с расплющиванием массивов подобного рода.

0

Вот решение для более общего случая, когда в вашем массиве могут быть элементы, которые не являются массивами:

function flattenArrayOfArrays(a, r) {
    if (!r) { r = []; }
    for (var i = 0; i < a.length; i++) {
        if (Array.isArray(a[i])) { // Используем Array.isArray для лучшей проверки
            flattenArrayOfArrays(a[i], r);
        } else {
            r.push(a[i]);
        }
    }
    return r;
}

В этом примере функция flattenArrayOfArrays принимает входной массив a и опциональный массив-результат r. Если r не передан, он инициализируется как пустой массив. Далее, для каждого элемента a, если элемент является массивом, функция вызывает сама себя рекурсивно. Если элемент не является массивом, он добавляется в результирующий массив r. В результате мы получаем плоский массив без вложенных массивов.

Использование Array.isArray() вместо проверки конструкции позволяет правильно обрабатывать любые объекты, которые могут быть "похоже на массив", но на самом деле не являются таковыми.

0

Вы можете использовать метод reduce(callback[, initialValue]) в JavaScript 1.8 для объединения всех элементов массива. Вот пример кода, который выполняет эту задачу:

list.reduce((p, n) => p.concat(n), []);

Этот код будет работать следующим образом: reduce проходит по каждому элементу массива list, передавая аккумулятор p (начальное значение - пустой массив) и текущий элемент n. В каждом шаге p.concat(n) объединяет аккумулятор с текущим элементом, что позволяет вам получить объединённый массив в конце. Обратите внимание, что если вам нужно просто объединить массивы, то можно использовать метод Array.prototype.flat() в более современных версиях JavaScript, который может быть проще и более читаемым.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь