How to turn dot notation string into an object in Javascript - javascript

I'm trying to turn a dot notation string into an object, for example given
[{
key: 'app.team.instance',
value: 'some value1'
}, {
key: 'app.team.instance.obj',
value: 'some value'
}, {
key: 'app.team.app.some',
value: 'some value'
}, {
key: 'app.service.awesome.more',
value: 'more values'
}]
I would like to turn it an object like to get
{
"team": {
"instance": "some value1",
"server": {
"obj": "some value"
},
"app": {
"some": "some value"
}
},
"service": {
"awesome": {
"more": "more values"
}
}
}
This's what I have tried using the following function. Looking at my function what have I missed or should improve?
function createObjFromRows(skip, key, value, obj) {
const ARRAY_KEYS = key.split('.');
const ARRAY_LENGTH = ARRAY_KEYS.length;
let i = skip ? 1 : 0;
for (; i < ARRAY_LENGTH; i++) {
if (i < (ARRAY_LENGTH - 1)) {
if (!obj.hasOwnProperty(ARRAY_KEYS[i])) { obj[ARRAY_KEYS[i]] = {}; }
} else {
obj[ARRAY_KEYS[i - 1]][ARRAY_KEYS[i]] = value;
}
}
}
This's what I get currently.
{
team: {
instance: 'some value1'
},
server: {
obj: 'some value'
},
app: {
some: 'some value'
},
service: {},
awesome: {
more: 'more values'
}
}

You can use array.prototype.reduce :
var datas = [ {key: 'app.team.instance', value: 'some value1'}, {key: 'app.team.server.obj', value: 'some value'}, {key: 'app.team.app.some',value: 'some value'}, {key: 'app.service.awesome.more', value: 'more values'}];
var res = datas.reduce((m, o) => {
var keys = o.key.split('.');
var cur = m;
keys.forEach((key, i) => {
if (i < keys.length - 1) {
cur[key] = cur[key] || {};
cur = cur[key];
} else {
cur[key] = o.value;
}
});
return m;
}, {});
console.log(res);

You could split the given key strings and save the last key for the assignment of the value after iterating the keys to the nested property.
var data = [{ key: 'app.team.instance', value: 'some value1' }, { key: 'app.team.server.obj', value: 'some value' }, { key: 'app.team.app.some', value: 'some value' }, { key: 'app.service.awesome.more', value: 'more values' }],
result = data.reduce(function (r, o) {
var path = o.key.split('.'),
last = path.pop();
path.reduce(function (p, k) {
return p[k] = p[k] || {};
}, r)[last] = o.value;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Object transformation using recursive function

I've got an object that looks like this:
{
parent: {
child1: {
key: 'value'
},
child2: {
key: 'value'
},
child3: {
key: 'value'
}
}
}
I need to transform it to an object that looks like this:
{
title: 'parent',
children: [{
title: 'child1',
children: [{
title: 'key',
value: 'value'
}]
}, {
title: 'child2',
children: [{
title: 'key',
value: 'value'
}]
}, {
title: 'child3',
children: [{
title: 'key',
value: 'value'
}]
}]
}
I ended up with a following function:
function transform(obj) {
const result = {
title: '',
children: []
};
for (let key in obj) {
let child = obj[key];
result.title = key;
if (typeof(child) === 'string') {
delete result.children;
result.value = child;
} else {
result.children.push(transform(child));
}
}
return result;
}
But when I run it, it returns me the following output, which is wrong:
{
title: 'parent',
children: [{
title: 'child3',
children: [
{ title: 'key', value: 'value' },
{ title: 'key', value: 'value' },
{ title: 'key', value: 'value' }
]
}]
}
Could anyone point out what exactly is my mistake in the function, please?
I think you've chosen the wrong base case for the tree recursion. Put the leaf detection at the top of the function, not in the loop:
function transform(title, value) {
if (typeof value === 'string') {
return {title, value};
} else {
const children = [];
for (let key in obj) {
children.push(transform(key, obj[key]));
}
return {title, children};
}
}
Since you only want the single child of the root node, you'd call it as
console.log(transform('parent', data.parent));
or
console.log(transform('', data).children[0]);
Here is what you want:
const o = {
parent: {
child1: {
key: 'value'
},
child2: {
key: 'value'
},
child3: {
key: 'value'
}
}
};
const r = {};
const struct = (root, c) => {
Object.entries(root).map(([k, v]) => {
if (typeof v === 'object') {
const el = { title: k, children: [] };
c.push(el);
struct(v, el.children);
} else {
c.push({ title: k, value: v });
}
});
}
r.title = 'parent';
r.children = [];
struct(o.parent, r.children);
console.log(r);
While the recursion here is fairly simple, you have an odd requirement. What would you expect if the root node had multiple properties?
I handle this with a wrapper function which uses the recursive one to build an array of similar nodes, but then takes only the first result. This seems far from ideal, but it works:
const _transform = (obj) =>
Object .entries (obj) .map (([k, v]) => ({
title: k,
...(Object (v) === v ? {children: _transform (v)} : {value: v})
}))
const transform = (obj) => _transform (obj) [0]
const input = {parent: {child1: {key: 'value'}, child2: {key: 'value'}, child3: {key: 'value'}}}
console .log (transform (input))
.as-console-wrapper {min-height: 100% !important; top: 0}
Alternate API
This code would be simpler with the API suggested by Bergi. This is the same idea as that code but with an implementation in my style:
const transform = (title, value) =>
Object (value) === value
? {title, children: Object .entries (value) .map (([k, v]) => transform (k, v))}
: {title, value}
const input = {parent: {child1: {key: 'value'}, child2: {key: 'value'}, child3: {key: 'value'}}}
console .log (
transform ('parent', input.parent)
)
.as-console-wrapper {min-height: 100% !important; top: 0}

Convert json to other json structure

I have an array of objects with this structure:
const treeData = [
{ 0: ["0-0", "0-1"] },
{ 1: ["1-0", "1-1"] }
]
It could be deeper but array data would be always json or strings
const treeData = [
{ 0: ["0-0", "0-1"] },
{ 1: ["1-0", "1-1"] },
2,
3
]
I would like to get something like this:
const treeDataResult = [
{
label: "0",
value: "0",
children: [
{
label: "0-0",
value: "0-0"
},
{
label: "0-1",
value: "0-1",
}
]
},
{
label: "1",
value: "1",
children: [
{
label: "1-0",
value: "1-0",
},
{
label: "1-1",
value: "1-1",
}
]
},
{
label: "2",
value: "2"
},
{
label: "3",
value: "3"
}
]
My code right now is this:
const treeData = [
{ "0": ["0-0", "0-1"] },
{ "1" : ["1-0", "1-1"] }
];
const convertNode = (parentNode) =>
parentNode.map(
childnode => {
if (typeof(childNode) === 'string')
return {
label: childNode,
value: childNode
}
else
return
childNode.map((key, val) =>
({
label: key,
value: key,
children: convertNode(val)
})
)
}
)
var treeDataResult = convertNode(treeData);
console.log(treeDataResult);
If JSON.parse is used to get the data, you can try something like this:
var j = '[ { "0": ["0-0", "0-1"] }, { "1": ["1-0", "1-1"] }, 2, 3 ]'
var o = JSON.parse(j, (k, v) => (k = v.constructor) === Array ? v :
k !== Object ? ({ label: v, value: v }) :
({ label: k = Object.keys(v)[0], value: k, children: v[k] }) )
console.log( o )
If the shape of your data is correct I've used reduce and map to get the data into the correct shape and the rest operator so that the objects are in one array
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
const treeData = [
{
0: ["0-0", "0-1"]
},
{
1: ["1-0", "1-1"]
},
{
2: null
},
{
3: []
},
{
4: ["0-1"]
}
]
const changeShape = data => {
return data.reduce((prev, curr) => [...prev, ...shape(curr)], []);
}
const shape = item => Object.keys(item).map(key => data(item, key));
const data = (item, key) => {
return !item[key] || !item[key].length > 0 ?
labelValue(key) :
{
...labelValue(key),
children: item[key].map(i => labelValue(i))
}
}
const labelValue = v => {
return {
label: v,
value: v
}
}
console.log(changeShape(treeData))
const treeData = [
{ "0": ["0-0", "0-1"] },
{ "1" : ["1-0", "1-1"] }
];
const convertNode = (parentNode) => {
console.log(parentNode)
return parentNode.map(
childNode => {
if (typeof childNode === 'string')
return {
label: childNode,
value: childNode
}
else
return {
label: Object.entries(childNode)[0][0],
value: Object.entries(childNode)[0][0],
children: convertNode(Object.entries(childNode)[0][1])
}
}
)
}
a primitive solution
const treeData = [
{ 0 : ["0-0", "0-1"] },
{ 1 : ["1-0", "1-1"] }
]
let treeDataResult = [];
for(i = 0; i < treeData.length; i++) {
let current = treeData[i],
label = Object.getOwnPropertyNames(current),
obj = {
label: label,
value: label,
children: []
}
for(j = 0; j < current[i].length; j++) {
let childData = current[i][j],
child = {
label : childData,
value : childData
}
obj.children.push(child)
}
treeDataResult.push(obj)
}
console.log(JSON.stringify(treeDataResult, null, 4));

how to write a loop for search array

I want to learn how to make this code cleaner. I am using JavaScript.
Here is an Array of Objects:
var arr = [
{ key: 'qqqqq', value: '11' },
{ key: 'aaaaa', value: '121' },
{ key: 'bbbbb', value: '131' },
{ key: 'ccccc', value: '141' },
]
var obj = { key: 'cccc', value: '-fd-' };
My target is to find if obj in arr(it means, arritem.key == obj.key), if it does, update the value, otherwise append the obj to arr.
The idea of a directly is:
let has = false;
for(const item of arr) {
if(item.key == obj.key) {
item.value = obj.value;
has = true;
break;
}
}
if(!has) {
arr.push(l);
}
It's there a cleaner way to achieve ?
Unless you're restricted to using that given format for the array, you can achieve what you want by turning it into an object or key/value pair...
var data = {
'qqqqq': '11',
'aaaaa': '121',
'bbbbb': '131',
'ccccc': '141'
}
then to add or update a value...
data['ccccc'] = '-fd-'; // updates ccccc
data['eeeee'] = 'new'; // adds eeeee
You could use Array#find for getting the object or if not found push obj to the array.
var arr = [{ key: 'qqqqq', value: '11' }, { key: 'aaaaa', value: '121' }, { key: 'bbbbb', value: '131' }, { key: 'ccccc', value: '141' }],
obj = { key: 'cccc', value: '-fd-' };
temp = arr.find(o => o.key === obj.key);
if (temp) {
temp.value = obj.value;
} else {
arr.push(obj);
}
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You've to first search if item exist in your array, you can use findIndex => if item is found just replace the value at the finded index by your new object else push it into your array.
var arr = [
{ key: 'qqqqq', value: '11' },
{ key: 'aaaaa', value: '121' },
{ key: 'bbbbb', value: '131' },
{ key: 'ccccc', value: '141' },
]
var obj = { key: 'cccc', value: '-fd-' };
var obj2 = { key: 'aaaaa', value: 'newValue' };
function updateOrPush(arr,obj){
var id = arr.findIndex(e => e.key == obj.key);
if(id > -1){
arr[id] = obj;
}
else{
arr.push(obj);
}
}
updateOrPush(arr,obj);
updateOrPush(arr,obj2);
console.log(arr)
Hope this code would be simpler
var arr = [
{ key: 'qqqqq', value: '11' },
{ key: 'aaaaa', value: '121' },
{ key: 'bbbbb', value: '131' },
{ key: 'ccccc', value: '141' },
]
var obj = { key: 'cccc', value: '-fd-' };
var objIndex = arr.findIndex(ele => ele.key === obj.key);
objIndex < 0 ? arr.push(obj) : arr[objIndex].value = obj.value;
console.log(arr);

Remove item from nested array by indices (recursion)

I have an array of nested objects. These objects take one of two forms:
// type a
{
value: 'some value'
}
or
// type b
{
array: [
object of type a or b,
object of type a or b,
...
]
}
So, the base array can be nested infinitely. Given a series of indices (I've been calling it a 'tree'), how can I remove a single item at any depth?
A sample of what I have so far:
const baseArray = [
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ value: 'some value' },
],
},
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ array: [
{ value: 'delete me' },
{ value: 'some value' },
]
},
],
},
],
}
]
const tree = [1, 3, 1, 0]
function deleteNested(tree, inputArray) {
const index = tree.shift();
console.log(inputArray, index);
const child = inputArray[index].array;
if (tree.length > 0) {
console.log(child)
return deleteNested(tree, child);
}
return [
...inputArray.slice(0, index),
...inputArray.slice(index + 1)
]
}
const originalArray = baseArray.slice(0);
console.log(deleteNested(tree, baseArray), originalArray);
I want to delete the marked object given it's 'tree' location: [1, 3, 1, 0]:
first, look in the 1 (index of 1, not 0) value of the initial array,
then the 3 value,
then look at the 1 value,
then finally remove the 0 value.
What I have above isn't working, but has gotten me started.
The function needs to be recursive to work at any depth. It should ideally not use splice() to avoid modifying the array passed into it -- rather, it should return a new one.
As i said in the comments if you know the number of iterations in advance you shouldn't use a recursive approach. A while loop is ideal such as;
function delNestedItem(a,dm){
var i = 0;
while (i < dm.length-1) a = a[dm[i++]].array;
a.splice(dm[i],1);
}
var data = [
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ value: 'some value' },
],
},
{ value: 'some value' },
{ array: [
{ value: 'some value' },
{ array: [
{ value: 'delete me' },
{ value: 'some value' },
]
},
],
},
],
}
],
delMark = [1, 3, 1, 0];
delNestedItem(data,delMark);
console.log(JSON.stringify(data,null,2));
Here's how you can do it in 1 reduce:
const baseArray = [{
value: 'some value'
}, {
array: [{
value: 'some value'
}, {
array: [{
value: 'some value'
}, {
value: 'some value'
}, ],
}, {
value: 'some value'
}, {
array: [{
value: 'some value'
}, {
array: [{
value: 'delete me'
}, {
value: 'some value'
}, ]
}, ],
}, ],
}];
const tree = [1, 3, 1, 0];
var deleted = tree.reduce(function(pos, pathIndex, index, arr) {
if (index + 1 < arr.length) {
return pos.array
? pos.array[pathIndex]
: pos[pathIndex];
} else {
pos.array = pos.array
.slice(0, pathIndex)
.concat(pos.array.slice(pathIndex + 1));
return pos;
}
}, baseArray);
console.log(baseArray);
You could generate a new array out of the given array only with the undeleted parts.
function ff(array, tree) {
function iter(array, level) {
var r = [];
array.forEach(function (a, i) {
if (tree[level] !== i) {
return r.push(a);
}
if (level + 1 !== tree.length && a.array) {
r.push({ array: iter(a.array, level + 1) });
}
});
return r;
}
return iter(array, 0);
}
var baseArray = [{ value: 'some value' }, { array: [{ value: 'some value' }, { array: [{ value: 'some value' }, { value: 'some value' }, ], }, { value: 'some value' }, { array: [{ value: 'some value' }, { array: [{ value: 'delete me' }, { value: 'some value' }, ] }, ], }, ], }],
tree = [1, 3, 1, 0],
copy = ff(baseArray, tree);
console.log(copy);
console.log(baseArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Merge JavaScript objects in array with same key

What is the best way to merge array contents from JavaScript objects sharing a key in common?
How can array in the example below be reorganized into output? Here, all value keys (whether an array or not) are merged into all objects sharing the same name key.
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
}, {
name: "foo2",
value: [
"val4"
]
}
];
Here is one option:-
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: ["val2", "val3"]
}, {
name: "foo2",
value: "val4"
}];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
Here is another way of achieving that goal:
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}];
var output = array.reduce(function(o, cur) {
// Get the index of the key-value pair.
var occurs = o.reduce(function(n, item, i) {
return (item.name === cur.name) ? i : n;
}, -1);
// If the name is found,
if (occurs >= 0) {
// append the current value to its list of values.
o[occurs].value = o[occurs].value.concat(cur.value);
// Otherwise,
} else {
// add the current item to o (but make sure the value is an array).
var obj = {
name: cur.name,
value: [cur.value]
};
o = o.concat([obj]);
}
return o;
}, []);
console.log(output);
2021 version
Using reduce to aggregate data.
Using logical nullish assignment only assigns if acc[name] is nullish (null or undefined).
Using Array.isArray to determines whether the passed value is an Array.
var arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];
const result = arrays.reduce((acc, {name, value}) => {
acc[name] ??= {name: name, value: []};
if(Array.isArray(value)) // if it's array type then concat
acc[name].value = acc[name].value.concat(value);
else
acc[name].value.push(value);
return acc;
}, {});
console.log(Object.values(result));
Using lodash
var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"}];
function mergeNames (arr) {
return _.chain(arr).groupBy('name').mapValues(function (v) {
return _.chain(v).pluck('value').flattenDeep();
}).value();
}
console.log(mergeNames(array));
Here is a version using an ES6 Map:
const arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];
const map = new Map(arrays.map(({name, value}) => [name, { name, value: [] }]));
for (let {name, value} of arrays) map.get(name).value.push(...[value].flat());
console.log([...map.values()]);
Use lodash "uniqWith". As shown below
let _ = require("lodash");
var array = [
{ name: "foo1", value: "1" },
{ name: "foo1", value: "2" },
{ name: "foo2", value: "3" },
{ name: "foo1", value: "4" }
];
let merged = _.uniqWith(array, (pre, cur) => {
if (pre.name == cur.name) {
cur.value = cur.value + "," + pre.value;
return true;
}
return false;
});
console.log(merged);
// output: [{ name: "foo1", value: "1,2,4" }, { name: "foo2", value: "3" }];
Using reduce:
var mergedObj = array.reduce((acc, obj) => {
if (acc[obj.name]) {
acc[obj.name].value = acc[obj.name].value.isArray ?
acc[obj.name].value.concat(obj.value) :
[acc[obj.name].value].concat(obj.value);
} else {
acc[obj.name] = obj;
}
return acc;
}, {});
let output = [];
for (let prop in mergedObj) {
output.push(mergedObj[prop])
}
It's been a while since this question was asked, but I thought I'd chime in as well. For functions like this that execute a basic function you'll want to use over and over, I prefer to avoid longer-written functions and loops if I can help it and develop the function as a one-liner using shallow Array.prototype functions like .map() and some other ES6+ goodies like Object.entries() and Object.fromEntries(). Combining all these, we can execute a function like this relatively easily.
First, I take in however many objects you pass to the function as a rest parameter and prepend that with an empty object we'll use to collect all the keys and values.
[{}, ...objs]
Next, I use the .map() Array prototype function paired with Object.entries() to loop through all the entries of each object, and any sub-array elements each contains and then either set the empty object's key to that value if it has not yet been declared, or I push the new values to the object key if it has been declared.
[{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]
Finally, to replace any single-element-arrays with their contained value, I run another .map() function on the result array using both Object.entries() and Object.fromEntries(), similar to how we did before.
let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));
This will leave you with the final merged object, exactly as you prescribed it.
let a = {
a: [1,9],
b: 1,
c: 1
}
let b = {
a: 2,
b: 2
}
let c = {
b: 3,
c: 3,
d: 5
}
let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));
getMergedObjs(a,b,c); // { a: [ 1, 9, 2 ], b: [ 1, 2, 3 ], c: [ 1, 3 ], d: 5 }
Try this:
var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"},{name:"foo2",value:"val5"}];
for(var j=0;j<array.length;j++){
var current = array[j];
for(var i=j+1;i<array.length;i++){
if(current.name = array[i].name){
if(!isArray(current.value))
current.value = [ current.value ];
if(isArray(array[i].value))
for(var v=0;v<array[i].value.length;v++)
current.value.push(array[i].value[v]);
else
current.value.push(array[i].value);
array.splice(i,1);
i++;
}
}
}
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
document.write(JSON.stringify(array));
This work too !
var array = [
{
name: "foo1",
value: "val1",
},
{
name: "foo1",
value: ["val2", "val3"],
},
{
name: "foo2",
value: "val4",
},
];
let arr2 = [];
array.forEach((element) => { // remove duplicate name
let match = arr2.find((r) => r.name == element.name);
if (match) {
} else {
arr2.push({ name: element.name, value: [] });
}
});
arr2.map((item) => {
array.map((e) => {
if (e.name == item.name) {
if (typeof e.value == "object") { //lets map if value is an object
e.value.map((z) => {
item.value.push(z);
});
} else {
item.value.push(e.value);
}
}
});
});
console.log(arr2);
const exampleObj = [{
year: 2016,
abd: 123
}, {
year: 2016,
abdc: 123
}, {
year: 2017,
abdcxc: 123
}, {
year: 2017,
abdcxcx: 123
}];
const listOfYears = [];
const finalObj = [];
exampleObj.map(sample => {    
listOfYears.push(sample.year);
});
const uniqueList = [...new Set(listOfYears)];
uniqueList.map(list => {   
finalObj.push({
year: list
});
});
exampleObj.map(sample => {    
const sampleYear = sample.year;  
finalObj.map((obj, index) => {     
if (obj.year === sampleYear) {        
finalObj[index] = Object.assign(sample, obj);       
}  
}); 
});
The final object be [{"year":2016,"abdc":123,"abd":123},{"year":2017,"abdcxcx":123,"abdcxc":123}]
const array = [{ name: "foo1", value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2", value: "val4"}];
const start = array.reduce((object, {name}) => ({...object, [name]: []}), {});
const result = array.reduce((object, {name, value}) => ({...object, [name]: [object[name], [value]].flat(2)}), start);
const output = Object.entries(result).map(([name, value]) => ({name: name, value: value}));
console.log(output);
try this :
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
}, {
name: "foo2",
value: [
"val4"
]
}
];
bb = Object.assign( {}, array, output );
console.log(bb) ;
A much more easier approach is this 2022:
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
},
{
name: "foo2",
value: [
"val4"
]
}
];
function mergeBasedOnKey(list){
let c = Object.values(list.reduce((a, b) => {
a[b.name] = a[b.name] || {name: b.name, value: []}
if(typeof(b['value']) == "string"){
a[b.name].value.push(b['value'])
}
else{
a[b.name].value = [...a[b.name].value, ...b.value]
}
return a
}, {}))
return c
}
let ans = mergeBasedOnKey(array)
console.log(ans)
I was looking for a quick, almost "one-liner" answer in this thread, provided that this is a trivial but common exercise.
I couldn't find any for my like. The other answers are fine but I am not much into boilerplate.
So, let me add one, then:
o = array.reduce((m,{name:n,value:v})=>({...m,[n]:[...m[n]||[],v].flat(1)}),{})
output = Object.entries(o).map(([n,v])=>({name:n,value:v}))
var array = [
{ name: "foo1", value: "val1"},
{ name: "foo1", value: ["val2","val3"] },
{ name: "foo2", value: "val4" }
]
o=array.reduce((m,{name:n,value:v})=>({...m,[n]:[...m[n]||[],v].flat(1)}),{})
output=Object.entries(o).map(([n,v])=>({name:n,value:v}))
console.log(output)

Categories

Resources