1. Почему это не удается?
Вы положили reduce
в неправильное место. Вы сводите список спецификаций, который уже был плоским массивом. Вы хотите сгладить список, который имеет имя и список спецификаций. Вот одна из возможностей:
const array = products.map(prod => [
prod.name,
prod.attributes.map(attr => attr.spec)
].reduce((acc, curr) => acc.concat(curr), []));
2. Какое решение лучше?
Как отмечает CertainPerformance, существует более простая версия, которую я мог бы написать немного иначе, как
const array = products.map(({name, attributes}) =>
[name, ...attributes.map(attr => attr.spec)]
);
3. Что делать, если мне нужно повторно использовать flatten
в других местах?
Извлеките его из первого решения как функцию многократного использования. Это не полная замена для нового метода Array flatten
, но это может быть все, что вам нужно:
const flatten = arr => arr.reduce((acc, curr) => acc.concat(curr), [])
const array = products.map(prod => flatten([
prod.name,
prod.attributes.map(attr => attr.spec)
])
)
4. Как это reduce
вызывает сглаживание одного уровня?
Мы можем думать о [x, y, z].reduce(fn, initial)
как о выполнении этих шагов
- Звоните
fn(initial, x)
, доходность a
- Call
fn(a, y)
, выходное значение b
- Звоните
fn(b, z)
, доходность c
- Поскольку массив исчерпан, возвращаемое значение
c
Другими словами [x, y, z].reduce(fn, initial)
возвращает fn(fn(fn(initial, x), y), z)
.
Когда fn
равно (acc, val) => acc.concat(val)
, тогда мы можем думать о ['name', ['spec1', 'spec2']].reduce(fn, [])
как fn(fn([], 'name'), ['spec1', 'spec2'])
, что совпадает с ([].concat('name')).concat(['spec1', 'spec2'])
, что, конечно, ['name', 'spec1', 'spec2']
.
5. Что-то не так с моим вопросом?
Я рад, что вы спросили. : -)
Был один существенный сбой. Вы не включили образцы данных. Чтобы решить эту проблему, нужно попытаться восстановить форматы данных из вашего кода. Было бы достаточно легко привести минимальный пример, такой как:
const products = [
{name: 'foo', attributes: [{spec: 'bar'}, {spec: 'baz'}]},
{name: 'oof', attributes: [{spec: 'rab'}, {spec: 'zab'}]}
]
с ожидаемым совпадением:
[
["foo", "bar", "baz"],
["oof", "rab", "zab"]
]
6. Как насчет моей структуры вывода?
Теперь, когда вы упомянули это, это кажется странной структурой. У вас могут быть на то веские причины, но это странно.
Массивы обычно служат двум целям в Javascript. Это либо списки произвольной длины элементов одного типа, либо списки фиксированной длины, с определенными типами в каждом индексе (иначе говоря, кортежи .)
Но ваша структура сочетает в себе оба из них. Это списки произвольной (по крайней мере, так кажется) длины, где первая запись - это имя, а последующие - спецификации. Хотя этому может быть оправдание, вы можете подумать о том, является ли эта структура особенно полезной.
7. Как я могу сделать это, не мутировав?
Если возможно, я бы хотел сделать это путем изменения массива.
Я отказываюсь принимать участие в таких ужасах.
Серьезно, однако, неизменяемые данные значительно упрощают кодирование. Есть ли реальная причина, по которой вы указали это в качестве требования?