Reputation: 8603
const data = [
1,2,3,4,5,[6,7,8],
]
function goEach(items) {
if (items.length) {
items.forEach((item) => goEach(item))
} else {
console.log(items);
}
}
let newList = [];
function buildNewList(items) {
if (items.length) {
items.forEach((item) => buildNewList(item))
} else {
newList.push(items);
// console.log(items);
}
}
let simList = [];
function buildSimList(items) {
if (items.length) {
items.forEach((item) => buildSimList(item))
} else {
simList.push({id: items, checked: false});
// console.log(items);
}
}
buildSimList
is what I am working on.
I know how to traverse each item as well as flattening a nested array with recursion. However, my brain getting stucked on the best way to produce an array with identical array structure but in different data format. For example, my buildSimList
should be converting the data
array into an array similar to this
[
{id: 1, clicked: false},
{id: 2, clicked: false},
{id: 3, clicked: false},
{id: 4, clicked: false},
{id: 5, clicked: false},
[
{id: 6, clicked: flase},
{id: 7, clicked: flase},
{id: 8, clicked: flase},
],
]
Is there an intuitive way to achieve it? I can't think of any. even using a library like lodash can be a good solution as well.
Upvotes: 1
Views: 84
Reputation: 135227
I would recommend a generic function like Array.prototype.map
but one the maps nested arrays too – we'll call it deepMap
.
const identity = x =>
x
const deepMap = (f = identity, xs = []) =>
xs.map (x =>
Array.isArray (x)
? deepMap (f, x)
: f (x))
const makeObject = (id = 0, clicked = false) =>
({ id, clicked })
const data =
[ 1, 2, 3, 4, 5, [ 6, 7, 8 ] ]
console.log (deepMap (makeObject, data))
// [ { id : 1, clicked : false }
// , { id : 2, clicked : false }
// , { id : 3, clicked : false }
// , { id : 4, clicked : false }
// , { id : 5, clicked : false }
// , [ { id : 6, clicked : false }
// , { id : 7, clicked : false }
// , { id : 8, clicked : false }
// ]
// ]
We get a better picture of how this works if we first understand map
, which only performs a shallow transformation – Below, we reimplement deepMap
but this time using our own implementation of map
const identity = x =>
x
const None =
Symbol ()
const map = (f = identity, [ x = None, ...xs ] = []) =>
x === None
? []
: [ f (x) , ...map (f, xs) ]
const deepMap = (f = identity, xs = []) =>
map (x =>
Array.isArray (x)
? deepMap (f, x)
: f (x), xs)
const makeObject = (id = 0, clicked = false) =>
({ id, clicked })
const data =
[ 1, 2, 3, 4, 5, [ 6, 7, 8 ] ]
console.log (deepMap (makeObject, data))
// [ { id : 1, clicked : false }
// , { id : 2, clicked : false }
// , { id : 3, clicked : false }
// , { id : 4, clicked : false }
// , { id : 5, clicked : false }
// , [ { id : 6, clicked : false }
// , { id : 7, clicked : false }
// , { id : 8, clicked : false }
// ]
// ]
Upvotes: 0
Reputation: 2920
When you want to transform an array to another array, the first thing to think of is map
. Given your requirements, here's my solution to your problem:
const data = [
1, 2, 3, 4, 5, [6, 7, 8]
];
const buildSimList = (array) =>
// transform array with map
array.map(item =>
// check if current item is array
item instanceof Array
// if it is an array then recursively transform it
? buildSimList(item)
// if not, then convert the number to an object
: { id: item, checked: false }
);
console.log(buildSimList(data));
Upvotes: 1
Reputation: 7916
Explanation uses symbols from my code snippet
When iterating data
within convert
we'll have to cover for 2 cases:
numOrArray
is a number, in which case we map it toObject
numOrArray
is an array, in which case we start a nested iteration. This may be a recursive call, since the logic is identical for nested arrays.// Converts given number to an object with id and clicked properties:
const toObject = (num) => ({ id: num, clicked: false });
// Iterates given data and converts all numbers within to
// objects with toObject. If an array is encountered,
// convert is called recursively with that array as argument.
const convert = (data) => {
return data.map((numOrArray) => Array.isArray(numOrArray)
? convert(numOrArray)
: toObject(numOrArray));
}
// Test drive!
const data = [1, 2, 3, 4, 5, [6, 7, 8]];
console.log(convert(data));
Upvotes: 2
Reputation: 48745
You were close since you do one object for non arrays and recurse when not, but you are adding to the same array and thus that will result in a flattened structure. Here is the same where each array become an array and each element become an object using higher order functions:
const data = [1,2,3,4,5,[6,7,8]]
function convert(e) {
return e instanceof Array ?
e.map(convert) :
{ id: e, clicked: false };
}
console.log(convert(data));
Also know that using the function twice won't give you the same oddity that you get the earlier result combined as in your code. The reson for that is that I do not use a global accumulator. Should I use an accumulator I would do something like this:
function convert(e) {
function helper(e, acc) {
...
}
return helper(e, []);
}
or if you really want mutation:
function convert(e) {
let acc = [];
function helper(e) {
acc.push(...);
}
helper(e);
return acc;
}
Upvotes: 2
Reputation: 33726
Use forEach
function along with recursion and check for the element's type using either typeof
keyword or instanceof
keyword.
const data = [1, 2, 3, 4, 5, [6, 7, 8]];
let convert = (acc /*This is the current accumulator*/ , array) => {
array.forEach((n) => {
if (n instanceof Array) {
let newAcc = []; // New accumulator because the iteration found an Array.
acc.push(newAcc);
convert(newAcc, n); // Recursion for the new accumulator
} else acc.push({ id: n, clicked: false });
});
};
let result = [];
convert(result, data);
console.log(result);
.as-console-wrapper {
max-height: 100% !important
}
Upvotes: 1
Reputation: 32176
Both converting items in a nested array, and flattening such an array are pretty simple if you use a recursive function.
All you have to do go through each item, and if it's not another array, perform the transformation you want. Otherwise, recurse. Here's an example for the data in your snippet:
const data = [1,2,3,4,5,[6,7,8]]
function convert(arr) {
return arr.map(item => {
if (item instanceof Array) return convert(item);
return {id: item, clicked: false};
});
}
const mapped = convert(data);
console.log(mapped);
function flatten(arr) {
return [].concat(...arr.map(item => {
if (item instanceof Array) return flatten(item);
return [item];
}));
}
const flat = flatten(mapped);
console.log(flat)
Upvotes: 1