Извлечь дочерние массивы из вложенных массивов
У меня есть вложенные данные массива, и я хотел бы извлечь все вложенные массивы, чтобы они были братьями и сестрами своего родителя. Я довольно близко, но я получаю дополнительный пустой массив в результатах, и я не могу понять, откуда он или от чего избавиться.
Примечание. Мне бы очень хотелось понять, почему это происходит и как избавиться от него в моей функции, а не только .filter(arr => arr.length)
в моем списке результатов.
Это моя попытка:
var arrs = [
[1, 2, [3, 4], 5],
[6, [7, 8, 9, [10, 11]]],
[12, 13],
[[14, 15], [16, 17]],
[[1], 4, [1, 1], 4]
];
// Desired Output
// [
// [1, 2, 5],
// [3, 4],
// [6],
// [7, 8, 9],
// [10, 11],
// [12, 13],
// [14, 15],
// [16, 17],
// [4, 4]
// [1]
// [1, 1]
// ]
function extractArrays (arr) {
return arr.reduce((res, curr) => {
if (Array.isArray(curr)) {
res = res.concat(extractArrays(curr));
}
else {
res[0].push(curr);
}
return res;
}, [[]]);
}
console.log(extractArrays(arrs));
// Results:
// [
// [], <-- Where is this coming from?
// [ 1, 2, 5 ],
// [ 3, 4 ],
// [ 6 ],
// [ 7, 8, 9 ],
// [ 10, 11 ],
// [ 12, 13 ],
// [], <-- Also here
// [ 14, 15 ],
// [ 16, 17 ],
// [ 4, 4 ],
// [ 1 ],
// [ 1, 1 ]
// ]
.as-console-wrapper {
max-height: 100% !important;
}
Ответы
Ответ 1
Элемент, подобный [[14, 15], [16, 17]]
, представит []
после рекурсии. Это нужно обработать путем проверки длины.
var arrs = [
[1, 2, [3, 4], 5],
[6, [7, 8, 9, [10, 11]]],
[12, 13],
[[14, 15], [16, 17]],
[[1], 4, [1, 1], 4]
];
function extractArrays (arr, acc=[]) {
if (arr.length == 0 ) return acc;
let pure = arr.filter(elm => !Array.isArray(elm));
if (pure.length > 0) {
acc.push(pure);
}
acc.concat(arr.filter(elm => Array.isArray(elm)).map(elm => extractArrays(elm, acc)));
return acc;
}
console.log(extractArrays(arrs));
Ответ 2
Вы можете попробовать следующий код
var arrs = [
[1, 2, [3, 4], 5],
[6, [7, 8, 9, [10, 11]]],
[12, 13],
[
[14, 15],
[16, 17]
], // <-- added additional test case
[
[1], 4, [1, 1], 4
]
];
function extractArrays(arr) {
return arr.reduce((res, curr, i) => {
if (Array.isArray(curr)) {
res = res.concat(extractArrays(curr));
} else {
let index = 0;
for (let j = 0; j <= i; j++) {
if (!Array.isArray(arr[j])) {
res[index] ? res[index].push(curr) : res.push([curr]);
break;
} else {
index++;
}
}
}
return res;
}, []); // <-- no initial empty array inside here
}
console.log(extractArrays(arrs));
Ответ 3
Вы можете проверить его при возврате из функции. stackblitz
function extractArray(arr) {
const res = arr.reduce((res, curr) => {
if(!Array.isArray(curr)){
return [[...res[0], curr], ...res.slice(1)]
}
return [...res, ...extractArray(curr)]
}, [[]]);
return res[0].length ? res : res.slice(1);
}
EDIT: более эффективная функция (проверьте связь stackblitz)
function extractFaster(arr) {
let res = [0];
function recExtract(arr) {
let hasNonArrayElm = false;
let index = res.length -1;
arr.forEach(curr => {
if (!Array.isArray(curr)) {
hasNonArrayElm ? res[index].push(curr) : res.splice(index, 0, [curr]);
hasNonArrayElm = true;
return;
}
recExtract(curr);
});
}
recExtract(arr);
res.splice(-1, 1)
return res;
}
Ответ 4
Я просто хотел поделиться своим подходом к этой проблеме, мне понравилось пытаться ее решить, в моем случае я также передал массив методу extractArrays
, чтобы упростить сбор и фильтрацию каждого массива внутри параметра arrs
.
let result = [];
extractArrays(arrs, result);
console.log(result);
function extractArrays(arr, result) {
let newResult = arr.reduce((acc, curr) => {
if (Array.isArray(curr)) {
extractArrays(curr, result);
} else {
acc.push(curr);
}
return acc;
}, []);
newResult.length && result.push(newResult);
}
Ответ 5
ОБНОВЛЕНИЕ: Ответ под строкой является отличным способом сгладить массивы, но я предложил это, потому что я неправильно понял этот вопрос. Я оставлю это, если кому-то будет полезно это знать, но для того, чтобы вести точный учет, я также обновлю свой ответ для решения проблемы, поставленной в вопросе.
Кажется, принятого ответа достаточно, но я попробую свои силы в этом. Я бы использовал Array.reduce
, чтобы покрыть все одним махом, а внутри использовал Array.filter
, чтобы отделить обычные элементы от элементов массива, а затем использовал бы оператор распространения ...
для вложенных массивов, чтобы все переместилось на один уровень, после рекурсивного вызова одной и той же функции extract для всех вложенных массивов. Честно говоря, объяснение может быть труднее понять, чем код, посмотрите:
const data = [
[1, 2, [3, 4], 5],
[6, [7, 8, 9, [10, 11]]],
[12, 13],
[[14, 15], [16, 17]],
[[1], 4, [1, 1], 4]
]
const extractChildArrays = arrs => arrs.reduce((acc, cur) => {
const nestedArrs = cur.filter(a => Array.isArray(a))
const normalItems = cur.filter(a => !Array.isArray(a))
acc.push(normalItems, ...extractChildArrays(nestedArrs))
return acc
}, [])
console.log(extractChildArrays(data))