JavaScript nested map() - javascript

I have an array:
const array = [
{name: "abc", numbers:[1,2]},
{name: "def", numbers:[3,4]}
];
I want to use .map() to return a new array like:
[
{name:"abc", number:1},
{name:"abc", number:2},
{name:"def", number:3},
{name:"def", number:4}
]
What should I do?

It would be more performant to use forEach instead of map.
As #MohammadUsman's nice answer shows, the output of map has to be flattened before you can get the result you want. With forEach (which returns nothing), you can just append to the output array directly:
const data = [
{ name: "abc", numbers: [1,2] },
{ name: "def", numbers: [3,4] }
];
var result = [];
data.forEach(
({ numbers, ...rest }) => numbers.forEach(
n => result.push(Object.assign({number: n}, rest )))
);
console.log(result);

You can iterate over input array using .map() and use Object.assign() to generate new object and finally flat the array using .flat() to get the desired output.
const data = [
{ name: "abc", numbers: [1,2] },
{ name: "def", numbers: [3,4] }
];
const result = data.map(
({ numbers, ...rest }) => numbers.map(n => Object.assign({number: n}, rest ))
).flat();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You could take directly Array#flatMap with an inner mapping of new objects and get an array of objects.
const
array = [{ name: "abc", numbers:[1, 2] }, { name: "def", numbers:[3, 4] }],
result = array.flatMap(({ name, numbers }) => numbers.map(number => ({ name, number })));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can use .reduce if flatmap not available. It is faster in your cases. Iteration will be only one time for each element.
const array = [
{ name: "abc", numbers: [1, 2] },
{ name: "def", numbers: [3, 4] },
];
const results = array.reduce((r, item) => {
r = r.concat(item.numbers.map((number) => ({ name: item.name, number })));
return r;
}, []);
console.log(results)

Here is a simple solution if you are up for using jquery...
const array = [
{name: "abc", numbers:[1,2]},
{name: "def", numbers:[3,4]}
];
var newArray = [];
$.each(array, function(k,v){
var strName = v.name;
$.each(v.numbers, function(key,value){
newArray.push({name: strName, number: value});
});
});
console.log(newArray);

Related

Efficient way to separate an array of objects based on another array

For example I have an array of objects and an array as such:
const arrayObj = [
{
id: 1,
name: "user1",
},
{
id: 2,
name: "user2",
},
{
id: 3,
name: "user3",
},
]
const array = ["user1", "user2"]
How is it I'm able to separate arrayObj into two arrays based on array as such:
const array1 = [
{
id: 1,
name: "user1",
},
{
id: 2,
name: "user2",
},
]
const array2 = [
{
id: 3,
name: "user3",
},
]
I was thinking maybe something like this:
const filteredArray = arrayObj.filter((el) => {
return array.some((f) => {
return f === el.name;
});
});
But is there a more efficient / quicker way?
Unless the arrays you're dealing with are huge, your current code is fine.
If the arrays are huge and the current code is too slow, put the names into a Set and check Set.has instead of Array.some - Set.has is much faster when there are many elements in the Set.
const userSet = new Set(array);
const usersInUserSet = arrayObj.filter(user => userSet.has(user.name));
const arr1 = [{id:'1',name:'A'},{id:'2',name:'B'},{id:'3',name:'C'},{id:'4',name:'D'}];
const arr2 = [{id:'1',name:'A',state:'healthy'},{id:'3',name:'C',state:'healthy'}];
const filterByReference = (arr1, arr2) => {
let res = [];
res = arr1.filter(el => {
return !arr2.find(element => {
return element.id === el.id;
});
});
return res;
}
console.log(filterByReference(arr1, arr2));

how to create 2 arrays by running once on an array containing objects with the arrays matching the fields?

for example - lets say I have the array -
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
I want to run once on that array and at the end of that run to have two arrays -
const arrayOne = ["first", "second"];
const arrayTwo = [1,2];
to get the first one is easy, but getting both at once?
I remember there was a way to do it but couldn't find it..
I'd appreciate any help!
Any looping logic will help
Array.reduce implementation will be like below
const array = [{ name: "first", val: 1 }, { name: "second", val: 2 }];
const [arrayOne, arrayTwo] = array.reduce((acc, curr) => {
const { name, val } = curr;
acc[0].push(name);
acc[1].push(val);
return acc;
}, [[], []]);
console.log(arrayOne, arrayTwo);
The function extractArrays is general-purpose and can be used in other cases as well.
function extractArrays(arr) {
const result = {};
for (obj of arr) {
for (key in obj) {
result[key] = (result[key] || []).concat([obj[key]]);
}
}
return result;
}
const array = [{name: "first", val: 1}, {name: "second", val: 2}];
const result = extractArrays(array);
const arrayOne = result.name;
const arrayTwo = result.val;
console.log(`arrayOne=${arrayOne}`);
console.log(`arrayTwo=${arrayTwo}`);
You can use Array.reduce to achieve this:
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
const result = array.reduce((res, item) => {
res[0].push(item.name)
res[1].push(item.val)
return res
}, [[], []])
console.log(result)
thanks everyone!
but I think that the easiest, most readable code would be something like -
const itemArray = [], valArray = [];
data.map(({name, val})=> {
if(name) nameArray.push(name);
if(val) valArray.push(val);
})
because basically in 4 lines of code it's finished
thanks again everyone!
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
const keys = [];
const values = [];
array.forEach(item=>{
keys.push(item.name);
values.push(item.val);
})
console.log(keys, values)
Use the Array.map function:
const array = [ { name: 'first', val: 1 }, { name: 'second', val: 2 } ]
let names = array.map(item => item.name)
let vals = array.map(item => item.val)
console.log(names)
console.log(vals)
The map function calls a callback function you provide on each element and constructs a new array from the results of that function.
If you are not familiar with arrow functions like:
item => item.name
... it is a short form for:
function (item) {
return item.name
}
You could even do it in one line:
let [ names, vals ] = [ array.map(item => item.name), array.map(item => item.val) ]

Array.from for array-of-objects. How to uniquely id each object?

I need to create an array that contains Nx duplicates of an input array-of-objects, and assign a unique ID to each individual object in the output array.
I know I can do the initial duplication, like so...
let input = [ { type: 123, name: 'apples'} , { type: 456, name: 'pears'} ]
let output = [ ...Array.from( {length: 3}, () => (input)) ].flat(1)
to get me..
[ { id: 123, name: 'apples'} , { id: 456, name: 'pears'}, { id: 123, name: 'apples'} , { id: 456, name: 'pears'}, { id: 123, name: 'apples'} , { id: 456, name: 'pears'} ]
but I don't know how, as part of that Array.from step, to add a unique ID to each object?
(Since each input object has it's own type, which is unique, I'd like to just combine that with it's set number, e.g. for the 1st & 3rd elements it's uniqueID would be 123-0, 123-1)
I know how to acheive it with for loops...
let output = []
for (let i=0; i<N; i++) {
for (let j = 0; j < input.length; j++) {
let newObject = { ...input[j] }
newObject.id = newObject.field1.ID+'-'+j
output.push(newObject)
}
}
but I'd like to learn how I could achieve the same whilst using Array.from, or some other similar function?
The callback argument of Array.from() is passed a collection element (which is undefined in your example) and an index. You can then map() over input and combine the type of each element with the current "set" index
let input = [ { type: 123, name: 'apples'} , { type: 456, name: 'pears'} ];
let output = Array.from(
{ length: 3 },
(_, i) => input.map((item) => ({ id: `${item.type}-${i}`, ...item }))
).flat(1);
console.log(output);
You can use the Array.map function
let output = [ ...Array.from( {length: 3}, () => (input)) ].flat(1).map((a, idx) => a = {...a, id: a.name.ID + '-' + idx})
You can use the callback function of the Array.from method to update the type. Check it out-
const input = [{type: 123, name: 'apples'} , {type: 456, name: 'pears'}];
const output = Array.from( {length: 3}, (_, i) => {
return input.map(item => ({...item, id: `${item.type}-${i}`}));
}).flat();
console.log(output);
.as-console-wrapper{min-height: 100%!important; top: 0}
Alternatively: a somewhat more generic multiplier function
const initial = [{
type: 123,
name: 'apples'
}, {
type: 456,
name: 'pears'
}];
const multiply = (initialArray, n = 3, serialKey = `type`) =>
[].concat(...[...Array(n)]
.map( (_, i) =>
initialArray.map( v => ({ ...v, [serialKey]: `${v[serialKey]}-${i}` }) ) )
);
console.log(multiply(initial, 4));

How to convert array to object in js?

I have got list of arrays .
let arr = ["one","two"]
My trying code is:
arr.map(item=>{
item
})
I want to convert array of sub-array
[
{
"one": [{
value: "one"
},
]
},
{
"two": [{
value: "two"
},
]
},
]
You can try with using Object.values().
const arr = ["one", "two"];
const result = Object.values(arr).map(e => {
return {
[e]: [{value: e}]
}
});
console.log(result);
you can also do it like this
let arr = ["one","two"]
arr.map(orgValue => {
[orgValue]: [
{
value: orgValue
}
]
};
);
A simple forEach loop would help
let arr = ["one", "two"];
var res = [];
arr.forEach(val => {
res.push({
[val]: [
{
value: val
}
]
});
});
console.log(res);

Making object from array with similar keys

I have an array like this:
var array = ['test1', 'test2', 'test3', 'test4']
I would like to make a new object from this array, and they should have the same keys. Desired outcome should be like this:
var objectFromArray = [
{ responsibilityName: "test1" },
{ responsibilityName: "test2" },
{ responsibilityName: "test3" },
{ responsibilityName: "test4"}
]
How is this possible in js?
Adjusted to your comment: you can use reduce and map to flatten the arrays within the array of objects.
[Edit based on your comment]
const arr = [
{ responsabilityName: ['test1', 'test2', 'test3', 'test4'],
somethingElse: [1, 2, 3, 4] } ];
const arrMapped = arr
.reduce( (mappedArr, obj) =>
Object.keys(obj)
.map( key => obj[key].map( prop => ({ [key]: prop }) ) )
.reduce( (p, n) => p.concat(n), [] ),
[] );
console.log(arrMapped);
Iterate over the array, create objects in the other one. As simple as that.
var array = ['test1', 'test2', 'test3', 'test4']
var objectFromArray = []
array.forEach((v)=>{objectFromArray.push({"responsibilityname":v})})
use array.map and assign the value to the object
DEMO
var array = ['test1', 'test2', 'test3', 'test4'];
var result = array.map(function(el) {
var obj = {};
obj['responsibilityname'] = el;
return obj;
})
console.log(array);
console.log(result);
Loop over the array and return a new object using map or forEach etc.
var array = ['test1', 'test2', 'test3', 'test4']
var arr = array.map(value => {
return {responsibilityName: value};
})
console.log(arr);

Categories