Вопрос по arrays, javascript – Объединить / сгладить массив массивов в JavaScript?

852

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

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

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

["$6", "$12", "$25", ...]
gist.github.com/Nishchit14/4c6a7349b3c778f7f97b912629a9f228 Эта ссылка описывает ES5 & amp; ES6 сплющить Nishchit Dhanani
Все решения, которые используютreduce + concat O ((N ^ 2) / 2), где в качестве принятого ответа (только один вызовconcat) будет не более O (N * 2) в плохом браузере и O (N) в хорошем. Также решение Denys оптимизировано для актуального вопроса и в 2 раза быстрее, чем единыйconcat, Дляreduce Мне нравится чувствовать себя классно, когда пишу крошечный код, но, например, если бы в массиве было 1000 подэлементов, состоящих из одного элемента, все решения, выполняемые с помощью Redu + + Concat, были бы полезны500500 operations где как один конкат или простой цикл будет делать 1000 операций. gman

Ваш Ответ

30   ответов
5

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;
}
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
15
const common = arr.reduce((a, b) => [...a, ...b], [])
24

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

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

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

[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded[[1], [2,3]].reduce( (a,b) => a.concat(b))
22

Еще одно решение 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]

UPDATE:

Рассмотрим также нативную функциюArray.prototype.flat () (предложение для ES6) доступно в последних выпусках современных браузеров.

Thanks to @(Константин Ван) and @(Mark Amery) mentioned it in the comments.

ПолучениеRangeError: Maximum call stack size exceeded
Это красиво и аккуратно, но я думаю, что вы сделали передозировку ES6. Нет необходимости, чтобы внешняя функция была функцией стрелки. Я бы придерживался функции стрелки для обратного обратного вызова, но само выравнивание должно быть нормальной функцией.
Error: User Rate Limit Exceeded
@StephenSimpson, но есть ли необходимость, чтобы внешняя функция былаnonError: User Rate Limit Exceeded"flatten itself ought to be a normal function"Error: User Rate Limit ExceededWhyError: User Rate Limit Exceeded
@ Matt, пожалуйста, поделитесь информацией, которую вы используете, чтобы воспроизвести ошибку
34

Существует новый собственный метод ECMA 2018, названныйплоский чтобы сделать это точно.

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]]
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Error: User Rate Limit ExceededECMAScript 2018Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
5

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

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

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

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

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

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

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;
}
Error: User Rate Limit ExceededrError: User Rate Limit Exceeded
Error: User Rate Limit ExceededObject.defineProperty(Array.prototype,'flatten',{value:function(r){for(var a=this,i=0,r=r||[];i<a.length;++i)if(a[i]!=null)a[i] instanceof Array?a[i].flatten(r):r.push(a[i]);return r}});
Этот подход был очень эффективен при выравнивании вложенных массивов форм наборов результатов, которые вы получаете отJsonPath query.
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededflattenArrayOfArrays (arr, 10)Error: User Rate Limit ExceededflattenArrayOfArrays(arr, [1,[3]]);Error: User Rate Limit Exceeded
3

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

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));
}
1478

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

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

console.log(merged);

С использованиемapply методconcat просто примет второй параметр как массив, поэтому последняя строка идентична этой:

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

Есть также экспериментальнаяArray.prototype.flat() метод (еще не являющийся частью стандарта ECMAScript), который можно использовать для выравнивания массивов, хотяон еще не доступен в Edge или Node.js.

const arrays = [
      ["$6"],
      ["$12"],
      ["$25"],
      ["$25"],
      ["$18"],
      ["$22"],
      ["$10"]
    ];
const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
console.log(merge3);
    

Error: User Rate Limit ExceededconcatError: User Rate Limit ExceededmergedError: User Rate Limit ExceededconcatError: User Rate Limit Exceededmerged = merged.concat.apply(merged, arrays);
Error: User Rate Limit Exceededvar merged = [].concat(...arrays)
Или жеArray.prototype.concat.apply([], arrays).
Error: User Rate Limit Exceeded
var merged = [].concat.apply([], arrays); кажется, работает нормально, чтобы получить его на одной строке. редактировать: как показывает ответ Никиты.
38

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

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

foresight

И да, вы правильно догадались, это только сплющиваетone уровень, который именно такshould Работа

Вообразите некоторый набор данных как это

// Player :: (String, Number) -> Player
const Player = (name,number) =>
  [ name, number ]

// team :: ( . Player) -> Team
const Team = (...players) =>
  players

// Game :: (Team, Team) -> Game
const Game = (teamA, teamB) =>
  [ teamA, teamB ]

// sample data
const teamA =
  Team (Player ('bob', 5), Player ('alice', 6))

const teamB =
  Team (Player ('ricky', 4), Player ('julian', 2))

const game =
  Game (teamA, teamB)

console.log (game)
// [ [ [ 'bob', 5 ], [ 'alice', 6 ] ],
//   [ [ 'ricky', 4 ], [ 'julian', 2 ] ] ]

Хорошо, теперь скажем, что мы хотим напечатать список, который показывает всех игроков, которые будут участвовать вgame & # X2026;

const gamePlayers = game =>
  flatten (game)

gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]

Если нашflatten процедура также сглаживает вложенные массивы, в результате мы получим этот мусорный результат & # x2026;

const gamePlayers = game =>
  badGenericFlatten(game)

gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]

rollin' deep, baby

Это не означает, что иногда вы также не хотите сглаживать вложенные массивы & # x2013; только это не должно быть поведением по умолчанию.

Мы можем сделатьdeepFlatten процедура с легкостью & # x2026;

// 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)

// deepFlatten :: [[a]] -> [a]
const deepFlatten =
  concatMap (x =>
    Array.isArray (x) ? deepFlatten (x) : x)

// your sample data
const data =
  [0, [1, [2, [3, [4, 5], 6]]], [7, [8]], 9]

console.log (flatten (data))
// [ 0, 1, [ 2, [ 3, [ 4, 5 ], 6 ] ], 7, [ 8 ], 9 ]

console.log (deepFlatten (data))
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Там. Теперь у вас есть инструмент для каждой работы & # x2013; один для раздавливания одного уровня вложенности,flattenи один для уничтожения всех вложенийdeepFlatten.

Может быть, вы можете назвать этоobliterate или жеnuke если вам не нравится имяdeepFlatten.


Don't iterate twice !

Конечно, вышеупомянутые реализации умны и кратки, но с использованием.map с последующим вызовом.reduce означает, что мы на самом деле делаем больше итераций, чем необходимо

Используя надежный комбинатор, который я вызываюmapReduce помогает сохранить итерации до минимума; требуется функция отображенияm :: a -> b, восстанавливающая функцияr :: (b,a) ->b и возвращает новую сокращающую функцию - этот комбинатор лежит в основеtransducers; если вы заинтересованы,Я написал о них другие ответы

// mapReduce = (a -> b, (b,a) -> b, (b,a) -> b)
const mapReduce = (m,r) =>
  (acc,x) => r (acc, m (x))

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

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

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

// flatten :: [[a]] -> [a]
const flatten =
  concatMap (id)
  
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
  concatMap (x =>
    Array.isArray (x) ? deepFlatten (x) : x)

// your sample data
const data =
  [ [ [ 1, 2 ],
      [ 3, 4 ] ],
    [ [ 5, 6 ],
      [ 7, 8 ] ] ]

console.log (flatten (data))
// [ [ 1. 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]

console.log (deepFlatten (data))
// [ 1, 2, 3, 4, 5, 6, 7, 8 ]

Error: User Rate Limit ExceededconcatError: User Rate Limit Exceededconcat ([[a]] -> [a]Error: User Rate Limit ExceededflattenError: User Rate Limit Exceededfoldr (++) []Error: User Rate Limit Exceededfoldr(concat) ([])Error: User Rate Limit Exceededconcat странное приложение ((++)Error: User Rate Limit Exceeded[a] -> [a] -> [a]Error: User Rate Limit Exceededa -> [a] -> [a].
Error: User Rate Limit ExceededflatMapError: User Rate Limit ExceededconcatMapError: User Rate Limit ExceededbindError: User Rate Limit ExceededlistError: User Rate Limit ExceededconcatpMap реализован какfoldr ((++) . f) []Error: User Rate Limit Exceededconst flatMap = f => foldr(comp(concat) (f)) ([])Error: User Rate Limit Exceededcomp.
Какова сложность этого алгоритма?
Error: User Rate Limit Exceeded
Часто, когда я вижу ваши ответы, я хочу отозвать свои, потому что они стали бесполезными. Отличный ответ!concatError: User Rate Limit Exceeded...Error: User Rate Limit ExceededapplyError: User Rate Limit Exceeded
46

Ты можешь использоватьНижнее подчеркивание:

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

_.flatten(x); // => [1, 2, 3, 4]
Error: User Rate Limit Exceededlearnyouahaskell.com
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededby specifying true for the second argument.
Error: User Rate Limit Exceeded
5

Я был лохом сES6 Генераторы на днях и написалэтот смысл, Который содержит...

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

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

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

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

Error: User Rate Limit ExceededPHP format
14

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

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

  • reusability
  • readability
  • conciseness
  • performance

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

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededconst flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);Error: User Rate Limit ExceededandError: User Rate Limit ExceededandError: User Rate Limit Exceeded
Error: User Rate Limit ExceededtheseError: User Rate Limit Exceeded
9

ES6 One Line Flatten

See 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

See 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]);
});
Error: User Rate Limit ExceededArray.prototype.concat.apply([], arr)Error: User Rate Limit ExceededconcatError: User Rate Limit Exceeded
23

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

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

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

Error: User Rate Limit ExceededjustError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded['foo', ['bar']]Error: User Rate Limit Exceeded['f', 'bar'].
Я бы сказал: «Не ищите более загадочные вещи». ^^
Error: User Rate Limit Exceeded
6

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

С этимJSON.stringify вывод, все, что осталось, это снять все скобки, обернуть результат командой start & amp; заканчивая скобки еще раз, и служите результат сJSON.parse что возвращает строку к «жизни».

  • Can handle infinite nested arrays without any speed costs.
  • Can rightly handle Array items which are strings containing commas.

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

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

console.log(flattened)

  • Only for multidimensional Array of Strings/Numbers (not Objects)
@GeorgeKatsanos - этот метод не будет работать для элементов массива (и вложенных элементов), которые не имеют примитивного значения, например, элемента, который указывает на элемент DOM
это, безусловно, самое быстрое решение, которое я видел для этого; знаете ли вы о каких-либо подводных камнях @vsync (за исключением того факта, что это выглядит немного странно - конечно, рассматривая вложенные массивы как строки: D)
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded["345", "2", "3,4", "2"]Error: User Rate Limit Exceeded
@realseanp - вы неправильно поняли значение этого элемента массива. Я намеренно ставлю эту запятую как значение, а не как запятую в виде массива Array, чтобы подчеркнуть силу моего решения над всеми остальными, что приведет к"3,4".
5

Я рекомендую экономить местофункция генератора:

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

При желании создайте массив сглаженных значений следующим образом:

let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]
Мне нравится этот подход. Похожий наstackoverflow.com/a/35073573/1175496Error: User Rate Limit Exceeded...Error: User Rate Limit Exceeded
3

В настоящее время лучший и простой способ сделать это - объединить и разбить массив следующим образом.

var multipleArrays = [["$6","$Demo"], ["$12",["Multi","Deep"]], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]]

var flattened = multipleArrays.join().split(",")

Это решение работает с несколькими уровнями, а также является однопользовательским.

DEMO

EDIT for ECMAScript 6

Поскольку ECMAScript 6 был стандартизирован, вы можете изменить операцию[].concat.apply([], arrays); за[].concat(...arrays);

var flattened = [].concat(...input);

DEMO

EDIT Most Efficient solution

Наиболее эффективный способ решения проблемы - использование цикла. Вы можете сравнить & quot; ops / sec & quot; скоростьВот

var flattened=[];
for (var i=0; i<input.length; ++i) {
    var current = input[i];
    for (var j=0; j<current.length; ++j)
        flattened.push(current[j]);
} 

DEMO

Надеюсь, поможет

Error: User Rate Limit Exceeded[[","]].join().split(",") не дает желаемого результата.
163

Лучше всего это сделать с помощью функции сокращения 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

Проблема соминания заключается в том, что массив не может быть пустым, поэтому вам нужно будет добавить дополнительную проверку.
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededmost of the time you don't need to pass a initialValue :)
@calbertts Просто передайте начальное значение[]Error: User Rate Limit Exceeded
Поскольку вы используете ES6, вы также можете использоватьthe spread-operator as array literal. arrays.reduce((flatten, arr) => [...flatten, ...arr])
4

Логика заключается в том, чтобы преобразовать входной массив в строку и удалить все скобки ([]) и проанализировать вывод в массив. Я использую функцию шаблона 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)
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededconst flatten = function (A) { return A .toString() .split(',') .reduce( (a,c) => { let i = parseFloat(c); c = (!Number.isNaN(i)) ? i : c; a.push(c); return a; }, []);
Пожалуйста, отредактируйте свой ответ, чтобы включить некоторые объяснения. Ответы только на код мало что делают для обучения будущих читателей SO. Ваш ответ находится в очереди на модерацию за низкое качество.
52

Update: it turned out that this solution doesn't work with large arrays. It you're looking for a better, faster solution, check out этот ответ.


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() и функции стрелок поддерживаются не всеми браузерами, но это не означает, что вы не можете использовать эти функции прямо сейчас. Просто используйтегалдеж & # X2014; он преобразует код ES6 в ES5.

@ LUH3417 Это не так, я очень ценю ваши комментарии. Оказалось, что вы правы - это решение действительно не работает с большими массивами. Я отправилanother answerError: User Rate Limit Exceeded
Error: User Rate Limit Exceededconst flatten = arr => [].concat(...arr)
ES6 оператор распространения, ftw
@GEMI Например, попытка сгладить массив из 500000 элементов с помощью этого метода дает «RangeError: Превышен максимальный размер стека вызовов».
Error: User Rate Limit ExceededapplyError: User Rate Limit Exceededapply/ распространять таким образом плохой совет, но так как никого не волнует ...
64

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

Вотthe fastest solution, which works also on arrays with multiple levels of nesting:

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;
};

Examples

Huge arrays

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

Он отлично справляется с огромными массивами. На моей машине выполнение этого кода занимает около 14 мс.

Nested arrays

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

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

Arrays with different levels of nesting

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

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

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededRangeError: Maximum call stack size exceededError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
7

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

ES5 способ дляflatten функция с резервным ES3 для N-кратных вложенных массивов:

var flatten = (function() {
  if (!!Array.prototype.reduce && !!Array.isArray) {
    return function(array) {
      return array.reduce(function(prev, next) {
        return prev.concat(Array.isArray(next) ? flatten(next) : next);
      }, []);
    };
  } else {
    return function(array) {
      var arr = [];
      var i = 0;
      var len = array.length;
      var target;

      for (; i < len; i++) {
        target = array[i];
        arr = arr.concat(
          (Object.prototype.toString.call(target) === '[object Array]') ? flatten(target) : target
        );
      }

      return arr;
    };
  }
}());

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

Error: User Rate Limit Exceeded
282

Вот простое и производительное функциональное решение:

var result = [].concat.apply([], [[1],[2,3],[4]]);
console.log(result); // [ 1, 2, 3, 4 ]

Нет императивного беспорядка.

Error: User Rate Limit Exceeded[[1],[2,3],[4]]Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded[].concat([[1],[2,3],[4]]...)
Error: User Rate Limit Exceeded... являются реальным кодом, а не многоточием.
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded[].concat([1],[2,3],[4],...).
7
var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);

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

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

7

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

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

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

Error: User Rate Limit Exceeded['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
5

Хаскельский подход

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
5

Похоже, это похоже на работу для рекурсии!

  • Handles multiple levels of nesting
  • Handles empty arrays and non array parameters
  • Has no mutation
  • Doesn't rely on modern browser features

Code:

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

Usage:

flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7] 
осторожный,flatten(new Array(15000).fill([1]))Error: User Rate Limit ExceededUncaught RangeError: Maximum call stack size exceededError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
415

Здесь короткая функция, которая использует некоторые из более новых методов массива 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]
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
@ayjay, это начальное значение аккумулятора для функции уменьшения, чтоmdnError: User Rate Limit ExceededflatError: User Rate Limit ExceededreduceError: User Rate Limit ExceededreduceError: User Rate Limit ExceededflatError: User Rate Limit Exceeded1Error: User Rate Limit ExceededflatError: User Rate Limit Exceeded1.concatError: User Rate Limit Exceeded
Error: User Rate Limit Exceededconst flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);
Error: User Rate Limit Exceededconst flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);

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