У меня есть массив JavaScript, например:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Как бы я хотел объединить отдельные внутренние массивы в один, например:
["$6", "$12", "$25", ...]
У меня есть массив JavaScript, например:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Как бы я хотел объединить отдельные внутренние массивы в один, например:
["$6", "$12", "$25", ...]
Вы можете использовать concat
для объединения массивов:
var arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
var merged = [].concat.apply([], arrays);
console.log(merged);
Здесь короткая функция, которая использует некоторые из новых методов массива 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]
Существует запутанно скрытый метод, который создает новый массив без изменения исходного:
var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 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), []);
Большинство ответов здесь не работают на огромных (например, 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]]]);
У него нет никаких проблем при сглаживании массивов, подобных этому.
Обновление: оказалось, что это решение не работает с большими массивами. Это вы ищете лучшее, более быстрое решение, посмотрите этот ответ.
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.
Существует новый собственный метод 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];
Вы можете использовать Underscore:
var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]
Общие процедуры означают, что нам не нужно переписывать сложность каждый раз, когда нам нужно использовать конкретное поведение.
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))
Решение для более общего случая, когда у вас могут быть некоторые элементы без массива в вашем массиве.
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;
}
Еще одно решение 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]) )
Как насчет использования метода JavaScript 1.8
reduce(callback[, initialValue])
JavaScript 1.8
list.reduce((p,n) => p.concat(n),[]);
Сделал бы работу.
Чтобы сгладить массив массивов из одного элемента, вам не нужно импортировать библиотеку, простой цикл является самым простым и наиболее эффективным решение:
for (var i = 0; i < a.length; i++) {
a[i] = a[i][0];
}
В downvoters: пожалуйста, прочитайте вопрос, не спускайте вниз, потому что это не подходит для вашей совершенно другой проблемы. Это решение является самым быстрым и простым в заданном вопросе.
const common = arr.reduce((a, b) => [...a, ...b], [])
Обратите внимание: Когда 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));
См. 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]);
});
См. 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]);
});
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))
Подход 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);
Если у вас есть только массивы с 1 строковым элементом:
[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
выполнит эту работу. Bt, который точно соответствует вашему примеру кода.
var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);
// gives ["a", "b", "c"]
(Я просто пишу это как отдельный ответ, основанный на комментарии @danhbear.)
Я рекомендую функцию генератора с эффективным использованием пространства:
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
Вы можете использовать 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)
Я предпочел бы преобразовать весь массив, как есть, в строку, но в отличие от других ответов, сделал бы это с помощью 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)
Похоже, что это выглядит как работа для 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]
Я сделал это с помощью рекурсии и закрытия
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;
}
На днях я баловался с 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 *.
Но опять же, я был просто дураком, так что я уверен, что есть более эффективные способы сделать это.
просто лучшее решение без lodash
let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
Это не сложно, просто перебирайте массивы и объедините их:
var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {
result = result.concat(input[i]);
}
Я предлагаю два коротких решения без рекурсии. Они не оптимальны с точки зрения вычислительной сложности, но работают в среднем в среднем:
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));
}
Логика здесь состоит в том, чтобы преобразовать входной массив в строку и удалить все скобки ([]) и разобрать вывод в массив. Я использую функцию шаблона 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)