Объединить/сгладить массив массивов

У меня есть массив JavaScript, например:

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

Как бы я хотел объединить отдельные внутренние массивы в один, например:

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

Ответ 1

Вы можете использовать concat для объединения массивов:

var arrays = [
  ["$6"],
  ["$12"],
  ["$25"],
  ["$25"],
  ["$18"],
  ["$22"],
  ["$10"]
];
var merged = [].concat.apply([], arrays);

console.log(merged);

Ответ 2

Здесь короткая функция, которая использует некоторые из новых методов массива JavaScript для выравнивания n-мерного массива.

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]

Ответ 3

Существует запутанно скрытый метод, который создает новый массив без изменения исходного:

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

Ответ 4

Лучше всего это сделать с помощью функции сокращения javascript.

var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];

arrays = arrays.reduce(function(a, b){
     return a.concat(b);
}, []);

Или с ES2015:

arrays = arrays.reduce((a, b) => a.concat(b), []);

js-скрипка

Документы Mozilla

Ответ 5

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

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

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]]]);

У него нет никаких проблем при сглаживании массивов, подобных этому.

Ответ 6

Обновление: оказалось, что это решение не работает с большими массивами. Это вы ищете лучшее, более быстрое решение, посмотрите этот ответ.


function flatten(arr) {
  return [].concat(...arr)
}

Просто расширяет arr и передает его как аргументы concat(), который объединяет все массивы в один. Это эквивалентно [].concat.apply([], arr).

Вы также можете попробовать это для глубокого сглаживания:

function deepFlatten(arr) {
  return flatten(           // return shalowly flattened array
    arr.map(x=>             // with each x in array
      Array.isArray(x)      // is x an array?
        ? deepFlatten(x)    // if yes, return deeply flattened x
        : x                 // if no, return just x
    )
  )
}

Смотрите демонстрацию на JSBin.

Ссылки на элементы ECMAScript 6, используемые в этом ответе:


Боковое примечание: методы, подобные find(), и функции стрелок не поддерживаются всеми браузерами, но это не значит, что вы не можете использовать эти функции прямо сейчас. Просто используйте Babel - он преобразует код ES6 в ES5.

Ответ 7

Существует новый собственный метод ECMA 2019, который называется flat, чтобы сделать это точно.

const arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

// Flatten 2 levels deep
const arr3 = [2, 2, 5, [5, [5, [6]], 7]];
arr3.flat(2);
// [2, 2, 5, 5, 5, [6], 7];

// Flatten all levels
const arr4 = [2, 2, 5, [5, [5, [6]], 7]];
arr4.flat(Infinity);
// [2, 2, 5, 5, 5, 6, 7];

Ответ 8

Вы можете использовать Underscore:

var x = [[1], [2], [3, 4]];

_.flatten(x); // => [1, 2, 3, 4]

Ответ 9

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

concatMap (или flatMap) - именно то, что нам нужно в этой ситуации.

// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
  xs.concat (ys)

// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
  xs.map(f).reduce(concat, [])

// id :: a -> a
const id = x =>
  x

// flatten :: [[a]] -> [a]
const flatten =
  concatMap (id)

// your sample data
const data =
  [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

console.log (flatten (data))

Ответ 10

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

function flattenArrayOfArrays(a, r){
    if(!r){ r = []}
    for(var i=0; i<a.length; i++){
        if(a[i].constructor == Array){
            r.concat(flattenArrayOfArrays(a[i], r));
        }else{
            r.push(a[i]);
        }
    }
    return r;
}

Ответ 11

Еще одно решение ECMAScript 6 в функциональном стиле:

Объявите функцию:

const flatten = arr => arr.reduce(
  (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
);

и используйте его:

flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]

 const flatten = arr => arr.reduce(
         (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
       );


console.log( flatten([1, [2,3], [4,[5],[6,[7,8,9],10],11],[12],13]) )

Ответ 12

Как насчет использования метода JavaScript 1.8 reduce(callback[, initialValue]) JavaScript 1.8

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

Сделал бы работу.

Ответ 13

Чтобы сгладить массив массивов из одного элемента, вам не нужно импортировать библиотеку, простой цикл является самым простым и наиболее эффективным решение:

for (var i = 0; i < a.length; i++) {
  a[i] = a[i][0];
}

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

Ответ 14

const common = arr.reduce((a, b) => [...a, ...b], [])

Ответ 15

Обратите внимание: Когда Function.prototype.apply ([].concat.apply([], arrays)) или оператор спреда ([].concat(...arrays)) используется для сглаживания массива, оба могут вызвать переполнение стека для больших массивов, поскольку каждый аргумент функции хранится в стеке.

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

  • повторное использование
  • читабельность
  • лаконичность
  • производительности

// small, reusable auxiliary functions:

const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); // aka reduce

const uncurry = f => (a, b) => f(a) (b);

const concat = xs => y => xs.concat(y);


// the actual function to flatten an array - a self-explanatory one-line:

const flatten = xs => foldl(concat) ([]) (xs);

// arbitrary array sizes (until the heap blows up :D)

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

console.log(flatten(xs));


// Deriving a recursive solution for deeply nested arrays is trivially now


// yet more small, reusable auxiliary functions:

const map = f => xs => xs.map(apply(f));

const apply = f => a => f(a);

const isArray = Array.isArray;


// the derived recursive function:

const flattenr = xs => flatten(map(x => isArray(x) ? flattenr(x) : x) (xs));

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

console.log(flattenr(ys));

Ответ 16

ES6 One Line Flatten

См. Lodash flatten, подчеркивание сглаженное (неглубокое true)

function flatten(arr) {
  return arr.reduce((acc, e) => acc.concat(e), []);
}

или

function flatten(arr) {
  return [].concat.apply([], arr);
}

Протестировано

test('already flatted', () => {
  expect(flatten([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});

test('flats first level', () => {
  expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, [3, [4]], 5]);
});

ES6 One Line Deep Flatten

См. Lodash flattenDeep, подчеркивание сгладить

function flattenDeep(arr) {
  return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}

Протестировано

test('already flatted', () => {
  expect(flattenDeep([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});

test('flats', () => {
  expect(flattenDeep([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]);
});

Ответ 17

ES6:

const flatten = arr => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flatten(next) : next), [])

const a = [1, [2, [3, [4, [5]]]]]
console.log(flatten(a))

Ответ 18

Подход Haskellesque

function flatArray([x,...xs]){
  return x ? [...Array.isArray(x) ? flatArray(x) : [x], ...flatArray(xs)] : [];
}

var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10];
    fa = flatArray(na);
console.log(fa);

Ответ 19

Если у вас есть только массивы с 1 строковым элементом:

[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');

выполнит эту работу. Bt, который точно соответствует вашему примеру кода.

Ответ 20

var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);

// gives ["a", "b", "c"]

(Я просто пишу это как отдельный ответ, основанный на комментарии @danhbear.)

Ответ 21

Я рекомендую функцию генератора с эффективным использованием пространства:

function* flatten(arr) {
  if (!Array.isArray(arr)) yield arr;
  else for (let el of arr) yield* flatten(el);
}

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

Ответ 22

Вы можете использовать Array.flat() с Infinity для любой глубины вложенного массива.

var arr = [ [1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]], [[1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]]] ];

let flatten = arr.flat(Infinity)

console.log(flatten)

Ответ 23

Я предпочел бы преобразовать весь массив, как есть, в строку, но в отличие от других ответов, сделал бы это с помощью JSON.stringify и не использовал метод toString(), который создавал бы нежелательный результат.

С этим выходом JSON.stringify все, что осталось, - это удалить все скобки, снова обернуть результат с помощью стартовых и конечных скобок и выполнить результат с помощью JSON.parse, который вернет строку в "жизнь".

  • Может обрабатывать бесконечные вложенные массивы без каких-либо затрат на скорость.
  • Можно корректно обрабатывать элементы массива, содержащие строки, содержащие запятые.

var arr = ["abc",[[[6]]],["3,4"],"2"];

var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]";
var flattened = JSON.parse(s);

console.log(flattened)

Ответ 24

Похоже, что это выглядит как работа для RECURSION!

  • Обработка нескольких уровней вложенности
  • Обрабатывает пустые массивы и параметры без массива
  • Не имеет мутации
  • Не полагается на современные функции браузера.

Код:

var flatten = function(toFlatten) {
  var isArray = Object.prototype.toString.call(toFlatten) === '[object Array]';

  if (isArray && toFlatten.length > 0) {
    var head = toFlatten[0];
    var tail = toFlatten.slice(1);

    return flatten(head).concat(flatten(tail));
  } else {
    return [].concat(toFlatten);
  }
};

Применение:

flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7] 

Ответ 25

Я сделал это с помощью рекурсии и закрытия

function flatten(arr) {

  var temp = [];

  function recursiveFlatten(arr) { 
    for(var i = 0; i < arr.length; i++) {
      if(Array.isArray(arr[i])) {
        recursiveFlatten(arr[i]);
      } else {
        temp.push(arr[i]);
      }
    }
  }
  recursiveFlatten(arr);
  return temp;
}

Ответ 26

На днях я баловался с ES6 Generators и написал эту суть. Который содержит...

function flatten(arrayOfArrays=[]){
  function* flatgen() {
    for( let item of arrayOfArrays ) {
      if ( Array.isArray( item )) {
        yield* flatten(item)
      } else {
        yield item
      }
    }
  }

  return [...flatgen()];
}

var flatArray = flatten([[1, [4]],[2],[3]]);
console.log(flatArray);

По сути, я создаю генератор, который зацикливается на исходном входном массиве, если он находит массив, он использует оператор yield * в сочетании с рекурсией для постоянного выравнивания внутренних массивов. Если элемент не является массивом, он просто возвращает один элемент. Затем с помощью оператора ES6 Spread (он же оператор splat) я сплющил генератор в новый экземпляр массива.

Я не проверял производительность этого, но я полагаю, что это хороший простой пример использования генераторов и оператора yield *.

Но опять же, я был просто дураком, так что я уверен, что есть более эффективные способы сделать это.

Ответ 27

просто лучшее решение без lodash

let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))

Ответ 28

Это не сложно, просто перебирайте массивы и объедините их:

var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];

for (var i = 0; i < input.length; ++i) {
    result = result.concat(input[i]);
}

Ответ 29

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

let a = [1, [2, 3], [[4], 5, 6], 7, 8, [9, [[10]]]];

// Solution #1
while (a.find(x => Array.isArray(x)))
    a = a.reduce((x, y) => x.concat(y), []);

// Solution #2
let i = a.findIndex(x => Array.isArray(x));
while (i > -1)
{
    a.splice(i, 1, ...a[i]);
    i = a.findIndex(x => Array.isArray(x));
}

Ответ 30

Логика здесь состоит в том, чтобы преобразовать входной массив в строку и удалить все скобки ([]) и разобрать вывод в массив. Я использую функцию шаблона ES6 для этого.

var x=[1, 2, [3, 4, [5, 6,[7], 9],12, [12, 14]]];

var y=JSON.parse(`[${JSON.stringify(x).replace(/\[|]/g,'')}]`);

console.log(y)