I have 2 objects:
const refer = [
{ key: 'A.ABC', value: 'ABC', display: 'ABC' },
{ key: 'A.PQR', value: 'INFOPQR', display: 'PQR' },
{ key: 'Q', value: 'Q', display: 'Q'},
]
const mapObj = [
{id: "A.ABC", name: "other value"},
{id: "A.PQR", name: "some values"},
]
I want to return a new object by applying a transform layer to mapObject that is basically like:
[
{id: "A.ABC", name: "other value"},
{id: "INFOPQR", name: "some values"},
]
notice that the value from refer object should be the id in mapObj only if the key of refer matches to id of mapobj.
const transform = refer => {
refer.map(r => {
const f = mapObj.filter(d => d.id === r.id);
});
}
I have the above so far. How do I use Object.assign to actually transform.
You can do this with map() and find() methods, and if key matches id from object in other array you can use Object.assign() to return new object else return current object.
const refer = [
{ key: 'A.ABC', value: 'ABC', display: 'ABC' },
{ key: 'A.PQR', value: 'INFOPQR', display: 'PQR' },
{ key: 'Q', value: 'Q', display: 'Q'},
]
const mapObj = [
{id: "A.ABC", name: "other value"},
{id: "A.PQR", name: "some values"},
]
const result = mapObj.map(o => {
const ref = refer.find(e => e.key == o.id)
return !ref ? o : Object.assign({}, o, {id: ref.value})
})
console.log(result)
Related
I'm attempting to create an array of objects as the final output which includes the parent name and it's children. The id would be the last child in the name
Sample output I'm trying to achieve :
[
{id:1,name:"1"},
{id:2,name:"1-2"},
{id:3,name:"1-2-3"},
{id:4,name:"1-2-4"}
]
Code:
let item = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
}
const createList = (item) => {
let name = item.children.map(e => {
return createList(e)
})
return item.name + "-" + name
}
console.log(createList(item))
A simple recursion will do the trick:
let item = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
}
var result = []
const createList = (items, acc) => {
items.forEach(item => {
const newAcc = {
id: item.id,
name: acc ? `${acc.name}-${item.name}` : `${item.name}`
}
result.push(newAcc)
createList(item.children, newAcc)
})
}
createList([item], null)
console.log(result)
You're on the right track with recursion, but the map function is probably not the best choice for this. Map function doesn't work the way you might expect when there is only one element in the array, as it is not meant to be used to process lists in such a way, but only to "map" data.
Try switching to a for loop or foreach and building the string yourself.
Example:
let sample = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
};
function buildArray(input, parentName) {
let output = [];
for (let item of input) {
let name = parentName ? `${parentName}-${item.name}` : item.name;
output.push({ id: item.id, name: name });
if (item.children) {
output = output.concat(buildArray(item.children, name));
}
}
return output;
}
let result = buildArray(sample.children, sample.name);
let output = document.getElementById('myresult');
output.innerText = JSON.stringify(result);
<p id="myresult"></p>
I think we can do this more simply. I'd prefer code like this:
const convert = ({id, name, children}, prefix = '') => [
{id, name: prefix + name},
...children .flatMap (c => convert (c, prefix + name + '-'))
]
const sample = {id: 1, name: "1", children: [{id: 2, name: "2", children: [{id: 3, name: "3", children: []}, {id: 4, name: "4", children: []}]}]}
console .log (convert (sample))
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that our recursion bottoms without an explicit case for it because mapping over an empty array returns an empty array, without making further calls. And that result is just folded into our accumulation by flatMap.
If you prefer not to include default parameters (and there are some good reasons for that preference), you could simply wrap an internal version of this function into a public function, supplying the initial prefix value to that internal one. This would also allow us to simplify the function reference passed to flatMap:
const _convert = (prefix = '') => ({id, name, children}) => [
{id, name: prefix + name},
...children .flatMap (_convert (prefix + name + '-'))
]
const convert = _convert ('')
const sample = {id: 1, name: "1", children: [{id: 2, name: "2", children: [{id: 3, name: "3", children: []}, {id: 4, name: "4", children: []}]}]}
console .log (convert (sample))
.as-console-wrapper {max-height: 100% !important; top: 0}
This question already has answers here:
group array of objects by id
(8 answers)
Closed 1 year ago.
I want to group the array of objects based on the key and concat all the grouped objects into a single array. GroupBy based on the id
example,
payload
[
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
expected response
[
[
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
}
],
[
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
]
All the matched elements are in the same array and all the arrays should be in a single array.
Array.redue will help
const input = [
{ id: 1, name: 'a' },
{ id: 1, name: 'b' },
{ id: 1, name: 'c' },
{ id: 2, name: 'b' },
{ id: 2, name: 'c' }
];
const output = input.reduce((acc, curr) => {
const node = acc.find(item => item.find(x => x.id === curr.id));
node ? node.push(curr) : acc.push([curr]);
return acc;
}, []);
console.log(output)
Extract the ids using Set so you have a unique set of them,
then loop over those ids and filter the original array based on it.
let objects = [
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
let ids = [...new Set(objects.map(i => i.id))]
let result = ids.map(id => objects.filter(n => id === n.id))
console.log(result)
you can create a object with ids array by using Array.reduce method, and get the object values by Object.values
var s = [{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
];
//go through the input array and create a object with id's, group the values to gather
var ids = s.reduce((a, c) => {
//check object has the `id` property, if not create a property and assign empty array
if (!a[c.id])
a[c.id] = [];
//push the value into desidred object property
a[c.id].push(c)
//return the accumulator
return a;
}, {});
//get the grouped array as values
var outPut = Object.values(ids);
console.log(outPut);
1) You can easily achieve the result using Map and forEach easily
const arr = [
{
id: 1,
name: "a",
},
{
id: 1,
name: "b",
},
{
id: 1,
name: "c",
},
{
id: 2,
name: "b",
},
{
id: 2,
name: "c",
},
];
const map = new Map();
arr.forEach((o) => !map.has(o.id) ? map.set(o.id, [o]) : map.get(o.id).push(o));
const result = [...map.values()];
console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
2) You can also achieve the result using reduce
const arr = [
{
id: 1,
name: "a",
},
{
id: 1,
name: "b",
},
{
id: 1,
name: "c",
},
{
id: 2,
name: "b",
},
{
id: 2,
name: "c",
},
];
const result = [...arr.reduce((map, curr) => {
!map.has(curr.id) ? map.set(curr.id, [curr]) : map.get(curr.id).push(curr);
return map;
}, new Map()).values()];
console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
I wonder how I can group this array based on the prefix text in name key (split the name key at the : colon) using Lodash.
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
to
const tags = [{
animals: [
{ name: 'Frogs', id: 1 },
{ name: 'Lions', id: 2 },
],
birds: [
{ name: 'Crows', id: 3}
]
}];
Does Lodash have any functions to handle this, or is a custom function/regex needed?
If the pure JS suffices, it can be done this way (the result is an object here, not an array, but this can be changed if needed):
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
const tags2 = tags.reduce(
(acc, { name, id }) => {
let [group, type] = name.split(': ');
group = group.toLowerCase();
acc[group] ??= [];
acc[group].push({ name: type, id });
return acc;
},
{},
);
console.log(tags2);
I am trying to figure out a sample array of object in which I have following key value pair. I need to find key which I am splitting based on underscore, first splitted value will become key and second will become the array of object of that key. I am getting duplicate key which needs to be unique and then add values into it.
const arr = [
{label: 'id', key: 'wfc_id'},
{label: 'Name', key: 'wfc_name'},
{label: 'Age', key: 'wfc_age'},
{label: 'id', key: 'ga_id'},
{label: 'Name', key: 'ga_name'},
{label: 'Age', key: 'ga_age'},
{label: 'Name', key: 'rtc_name'},
{label: 'id', key: 'rtc_id'},
]
Desired Ouput:
output = {
wfc: {id:true, name:true, age: true},
ga: {id:true, name:true, age: true},
rtc: {id:true, name:true},
}
I tried following code:
let output = Object.assign({},arr.map((item) => {
let str = item.key.split('_');
let obj = {};
obj[str[0]] = {
[str[1]]: true
}
return obj
})
);
console.log(output);
But it giving me output as
{
"0": {
"wfc": {
"id": true
}
},
"1": {
"wfc": {
"name": true
}
},
"2": {
"wfc": {
"age": true
}
},
"3": {
"ga": {
"id": true
}
},
"4": {
"ga": {
"name": true
}
},
"5": {
"ga": {
"age": true
}
},
.......
}
I require if key already exits then add array/object for it's corresponding key
The map() function returns a new array. To transform the output, you need to reduce(), also called a "fold."
arr.reduce((acc, curr) => {
const split = curr.key.split('_');
const identifier = split[0];
const property = split[1];
acc[identifier] = { ...acc[identifier], [property]: true };
return acc;
}, {});
You're better off using reduce in this case. You present it with an initial object (accumulator), and then add to it over the iterations.
const arr = [
{label: 'id', key: 'wfc_id'},
{label: 'Name', key: 'wfc_name'},
{label: 'Age', key: 'wfc_age'},
{label: 'id', key: 'ga_id'},
{label: 'Name', key: 'ga_name'},
{label: 'Age', key: 'ga_age'},
{label: 'Name', key: 'rtc_name'},
{label: 'id', key: 'rtc_id'},
]
const output = arr.reduce((acc, item) => {
// Destructure the array into a key and value
let [ key, value ] = item.key.split('_');
// If the key doesn't exist on the accumulator
// add an empty object
acc[key] = acc[key] || {};
// And then set the object property to true
acc[key][value] = true;
// Return the accumulator for the next iteration
return acc;
}, {});
console.log(output);
You may use reduce for your case.
const arr = [
{ label: "id", key: "wfc_id" },
{ label: "Name", key: "wfc_name" },
{ label: "Age", key: "wfc_age" },
{ label: "id", key: "ga_id" },
{ label: "Name", key: "ga_name" },
{ label: "Age", key: "ga_age" },
{ label: "Name", key: "rtc_name" },
{ label: "id", key: "rtc_id" },
];
const o = arr.reduce((a, b) => {
const [key, prop] = b.key.split("_");
a[key] ? (a[key][prop] = true) : (a[key] = { [prop]: true });
return a;
}, {});
console.log(o);
What we want to do is to use a single schema create a new array (with the values of arrObj:
const arrObj = [{
id: 1,
title: 'aaa'
}, {
id: 2,
title: 'bbb',
}]
const schema = [{
name: 'id',
value: ''
}, {
name: 'title',
value: ''
}]
const finalArrObj = []
arrObj.forEach(eachArrObj => {
const eachArr = [...schema] // copy array without pointing to the original one
eachArr.forEach(field => {
field.value = eachArrObj[field.name]
console.log('1: ' , field) // correct value
})
console.log('2: ', eachArr) // the objects are all the same
console.log('3: ', eachArr[0].value) // the object here is correct
finalArrObj.push(eachArr)
})
For some reason, the values in console log number 2 logs an array with the same object. Console log number 3 logs the correct object.
Why is this happening and how to fix it?
Live example: https://codepen.io/sky790312/pen/KmOgdy
UPDATE:
Desired result:
[{
name: 'id',
value: '1'
}, {
name: 'title',
value: 'aaa'
}],
[{
name: 'id',
value: '2'
}, {
name: 'title',
value: 'bbb'
}]
You could map new objects by using Object.assign for schema, before assigning values to it.
schema.map(a => Object.assign({}, a, { value: o[a.name] }))
^^^^^^^^^^^^^^^^ take empty object for
^ assingning values of a and
^^^^^^^^^^^^^^^^^^^^ only the value of a property
const arrObj = [{ id: 1, title: 'aaa' }, { id: 2, title: 'bbb' }],
schema = [{ name: 'id', value: '' }, { name: 'title', value: '' }],
finalArrObj = arrObj.map(o =>
schema.map(a => Object.assign({}, a, { value: o[a.name] }))
);
console.log(finalArrObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You have to copy the inner object also, replace this
const eachArr = [...schema];
with this
const eachArr = schema.map((e)=>{
return Object.assign({}, e);
})