Я хочу объединить несколько массивов в один массив.
Я попробовал _.zip из библиотеки лодаш, но это не то, что мне нужно.
Вот массивы:
var arr1 = [
'a', 'b'
];
var arr2 = [
'c', 'd'
];
var arr3 = [
'e'
];
И я хочу этот вывод:
var result = [
['a', 'c', 'e'],
['a', 'd', 'e'],
['b', 'c', 'e'],
['b', 'd', 'e']
];
Нужно ли работать для произвольного количества начальных массивов?
Я нашел этот смысл, который использует lodash, который может оказаться полезным. gist.github.com/wassname/a882ac3981c8e18d2556 Используйте комбинированную функцию с разбросом 3 массивов combinations([...a1, ...a2, ...a3], 3)
. Или декартово произведение, как сказал другой человек.
То, что вы ищете, называется «Декартово произведение». Здесь есть решения: stackoverflow.com/questions/12303989/…
@RobG в теме, на которую я ссылаюсь, есть много ответов, большинство из которых не использует какие-либо внешние библиотеки.
Если вы ожидаете, что у вас всегда будет одинаковое количество массивов, я нахожу это более читаемым, хотя и немного избыточным:
let arr1 = [
'a', 'b'
];
let arr2 = [
'c', 'd'
];
let arr3 = [
'e'
];
let result = arr1.flatMap(one =>
arr2.flatMap(two =>
arr3.map(three => [one, two, three])));
console.info(result);
Если вы не всегда ожидаете 3 массива или предпочитаете общую функцию для умножения произвольного количества массивов:
let arr1 = [
'a', 'b'
];
let arr2 = [
'c', 'd'
];
let arr3 = [
'e'
];
let multiply = (...arrays) =>
arrays.reduce((results, array) =>
results.flatMap(result => array.map(a => [...result, a])), ['']);
let results = multiply(arr1, arr2, arr3);
console.info(results);
Второй не работает. ...result
на самом деле распространяет строку. Поскольку это строки с одним символом, это работает. Если вы попробуете с [ 'aa', 'bb' ]
, вы увидите это
хороший улов. фиксированный.
Как уже отмечали другие, это называется декартовым произведением ваших массивов. Мне проще построить его, сложив (reducing
) над тем, который берет произведение двух массивов.
const product = (xs, ys) =>
xs .flatMap (x => ys .map (y => [x, y] .flat () ) )
const productAll = (...xss) =>
xss .reduce (product)
console .log (
productAll ( ['a', 'b'], ['c', 'd'], ['e'])
)
Если ваша среда не поддерживает поддержите flat
и flatmap
, их довольно легко скрыть.
Если вы хотите предоставить массивы внутри одного массива [['a', 'b'], ['c', 'd'], ['e']]
, а не по отдельности, просто замените ...xss
на xss
.
Несколько человек уже упомянули, что ваш вопрос является дубликатом этот вопрос. Итак, вы можете посмотреть там рекомендуемое решение.
Я просто хотел добавить еще одно функциональное решение, которое можно произвольно комбинировать. Функция listProduct
в этом случае имеет тип listProduct :: [[a]] -> [a] -> [[a]]
, что означает, что она принимает (как минимум) двумерный массив в качестве первого аргумента и возвращает его. Вот почему функция singletonize
необходима для преобразования первого массива в двумерный массив.
Как показано ниже, вы можете легко комбинировать вызовы этой функции, чтобы получить произведение n (n ≥ 2) списка, если хотите.
const singletonize = l => l.map(x => [x])
const listProduct = (ls, list) =>
ls.reduce((r, l) => {
combinations = list.map(x => l.concat(x))
return r.concat(combinations)
}, [])
// The three arrays of your example
const a_1 = ['a', 'b'];
const a_2 = ['c', 'd'];
const a_3 = ['e'];
console.info(listProduct(listProduct(singletonize(a_1), a_2), a_3))
// Another example with five arrays
const a_4 = ['f', 'g', 'h'];
const a_5 = ['i'];
console.info(listProduct(listProduct(listProduct(listProduct(singletonize(a_1), a_2), a_3), a_4), a_5))
Вы можете взять функцию декартова произведения заданных массивов.
const cartesian = (...p) =>
p.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
var a = ['a', 'b'],
b = ['c', 'd'],
c = ['e'];
result = cartesian(a, b, c);
result.forEach(a => console.info(...a));
Этого добились бы три вложенных цикла.