2016-07-23 5 views
0

Я хочу определить функцию .flatten, которая сглаживает несколько элементов в один массив. Я знаю, что следующий не представляется возможным, но, по сути, я хотел бы сделать это:Как бы вы использовали .reduce() для аргументов вместо определенного массива или объекта?

var flatten = function() { 
    var flattened = arguments.reduce(function(acc, elem) { return acc.concat(elem) }, []); 
    return flattened; 
}; 

var arr = [[1,2,3], 4, 5, [6, 7]]; 
console.log(flatten(arr)) // => [1,2,3,4,5,6,7] 

Я получаю следующее сообщение об ошибке:

TypeError: arguments.reduce is not a function 

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

var flatten = function() { 
    var flattened = [].reduce.call(arguments, function(acc, elem) { return acc.concat(elem) }); 
    return flattened; 
}; 

Любой хороший способ переписать .flatten используя .reduce()?

ПРИМЕЧАНИЕ: Я знаю, что есть много других способов, которыми вы можете сглаживать массивы в javascript, но мне было интересно, как это сделать с конкретными аргументами .

+0

'reduce' не хорошо для выравнивания массивов. Кроме того, ваш код работает. – 4castle

+0

Когда вы использовали '.call()', вы забыли передать пустой массив в качестве второго аргумента в '.reduce()'. – nnnnnn

+0

Возможный дубликат [Слияние/сглаживание массива массивов в JavaScript?] (Http://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript) – 4castle

ответ

4

Преобразование arguments объекта в массив первый:

var flatten = function() { 
    var args = Array.prototype.slice.call(arguments); 
    var flattened = args.reduce(function(acc, elem) { return acc.concat(elem) }, []); 
    return flattened; 
}; 

Или, методы использования массивов на arguments объекте непосредственно:

var flatten = function() { 
    var flattened = Array.prototype.reduce.call(arguments, function(acc, elem) { return acc.concat(elem) }, []); 
    return flattened; 
}; 

В ES6, вы можете использовать Array.from() для преобразования любой итерации или массив-подобный объект к фактическому массиву:

var flatten = function() { 
    var args = Array.from(arguments); 
    var flattened = args.reduce(function(acc, elem) { return acc.concat(elem) }, []); 
    return flattened; 
}; 

FYI, есть много способов, чтобы сгладить массив:

Merge/flatten an array of arrays in JavaScript?

How to flatten nested array in javascript?

Flattening multidimensional Arrays in JavaScript

+0

Спасибо! Это именно то, что я искал, я не знал, что аргументы могут быть полностью преобразованы в такой массив. –

1

Использование Array.prototype.concat.apply([], arguments)

function flatten() { 
 
    return Array.prototype.concat.apply([], arguments); 
 
} 
 

 
console.log(flatten([1, 2], 3, 4, [5, 6]));

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

[].concat.apply([], arguments) 

В ES6, хотя, вы можете получить лучшее из обоих миров:

[].concat(...arguments) 
+0

Спасибо, это выглядит очень чисто. Вы сказали: «Если вы не против создания неиспользуемого пустого массива». Просто интересно, есть ли недостатки для этого? –

+0

@AljoshaNovakovic Это просто создаст дополнительную вещь для сбора мусора. – 4castle

0

Вы также можете проверить, если элементы subArraythis образом:

function flatten(arr){ 
    var res = []; 
    arr.forEach(x => Array.isArray(x) ? x.forEach(y => res.push(y)) : res.push(x)); 
    return res; 
} 

console.log(flatten([[1,2,3], 4, 5, [6, 7]])); // [ 1, 2, 3, 4, 5, 6, 7 ] 
+0

спасибо!В вашем примере вы прошли в одном массиве (с субмассивами), но я заметил, что это сработает, даже если ваш аргумент будет иметь дополнительные отдельные аргументы. Он сглаживает ВСЕ, мило. –

+0

Это может сгладить только один массив. Он не совсем подходит к другим, где любое количество массивов может быть передано 'flatten'. – 4castle

0

Что-то вроде этого:

BTW: Я думаю, с помощью push лучше concat, поскольку это не создает новый массив

function flatten() 
{ 
    return flatten0([], Array.from(arguments)); 

    function flatten0(res, arrToFlatten) 
    { 
    for (let el of arrToFlatten) 
     Array.isArray(el) ? flatten0(res, el) : res.push(el); 
    return res; 
    } 
}; 

let arr = [1, 2, [3, 4], [[5, [6], [[7]]]]]; 
console.log(flatten(arr)) // [ 1, 2, 3, 4, 5, 6, 7 ] 
+0

Объявление функции внутри функции - это плохая практика. Каждый раз, когда вызывается 'flatten', ему нужно будет воссоздать' flatten0' – 4castle

+0

@ 4castle. Я не думаю, что 'flatten0' нужно воссоздавать каждый раз (создание его однажды должно быть прекрасным, так как оно не использует никаких переменных из внешняя функция). Есть ли способ проверить ваше заявление? –

+0

[Этот вопрос] (http://stackoverflow.com/q/10204420/5743988) объясняет это хорошо. Вы будете во власти механизма сценариев, будь он оптимизирован или нет. Хорошим решением является использование IIFE (как указано в 2-м и 3-м ответе) – 4castle

 Смежные вопросы

  • Нет связанных вопросов^_^