Related
This question already has answers here:
Convert array of objects with same property to one object with array values
(6 answers)
Closed 2 months ago.
I have an array of objects that looks like this:
arr = [
{name: "john", age: 23},
{name: "mary", age: 40},
{name: "zack", age: 17}
]
I am trying to convert it into something like this:
{
name: ["john", "mary", "zack"],
age: ['23', 40, 17]
}
i have tried the following
arr.map(item => item.name)
arr.map(item => item.age)
return {names, ages}
and it works fine but this assumes that you already know, beforehand, the keys of the objects you're converting.
I want to be able to load the object keys and corresponding array of values dynamically. Assuming i don't know that the objects in our example array have "name" and "age" as keys.
You could reduce the array and the entries of the object and collect the values in the group of the keys.
const
data = [{ name: "john", age: 23 }, { name: "mary", age: 40 }, { name: "zack", age: 17 }],
result = data.reduce((r, o) => Object.entries(o).reduce((t, [k, v]) => {
if (!t[k]) t[k] = [];
t[k].push(v);
return t;
}, r), {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could get the key of the first element and then map through it. With each, get its corresponded values
const arr = [
{ name: "john", age: 23, gender: "male" },
{ name: "mary", age: 40, gender: "female" },
{ name: "zack", age: 17, gender: "male" },
]
const res = Object.keys(arr[0]).reduce((acc, el) => {
const values = arr.map((item) => item[el])
return { ...acc, [el]: values }
}, {})
console.log(res)
Assuming that each object in your list has the same keys you could get the keys of the first object
const keys = Object.keys(arr[0])
and then map through the keys with your above approach
const returnObj = {}
keys.forEach(key => {
returnObj[key] = arr.map(item => item[key])
})
return returnObj
You can use Object.entries for the mapping.
var arr = [
{name: "john", age: 23},
{name: "mary", age: 40},
{name: "zack", age: 17}
];
var entries = arr.map((item) => Object.entries(item));
var result = {};
entries.forEach(entry => {
entry.forEach(item => {
if (result[item[0]] && result[item[0]].length > 0) {
result[item[0]].push(item[1]);
} else {
result[item[0]] = [item[1]];
}
});
});
console.log(result);
You can make use of Array.reduce and Object.keys.
let arr = [
{name: "john", age: 23},
{name: "mary", age: 40},
{name: "zack", age: 17}
]
const formatData = (data) => {
return data.reduce((res, obj) => {
Object.keys(obj).map(d => {
res[d] = [...(res[d] ||[]), obj[d]]
})
return res;
}, {})
}
console.log(formatData(arr))
You can do this with Ramda
import { mergeWith, concat } from “Ramda”
const mergeConcat = mergeWith(concat)
mergeConcat(arr)
I have this list
{
'0': { id: 'id3', name: 'Capitan America', job: 'superHero' },
'1': { id: 'id4', name: 'Spider-man', job: 'Pro footballer' }
}
And i want to change my keys to the id value like this:
{
id3 : { id: 'id3', name: 'Capitan America', job: 'superHero' },
id4 : { id: 'id4', name: 'Spider-man', job: 'Pro footballer' }
}
this is what i have tried in my code where in my fetch items i transform an array of objects into an object of objects and when i transform into one object of object my keys stayed like the index of the array:
fetchItems() {
const objectified = Object.assign({},this.list)
return objectified;
}
When you use Object.assign to assign an array to an object, indices of the array will become properties of the assigned object. The best way to construct your desired object is to build it manually.
Modify your fetchItems as below:
function fetchItems() {
const result = {};
for (const item of list)
result[item.id] = item;
return result;
}
Here is one way to do what you are asking by stepping over each property, building a new object.
var objA = {
'0': { id: 'id3', name: 'Capitan America', job: 'superHero' },
'1': { id: 'id4', name: 'Spider-man', job: 'Pro footballer' }
};
function transform(obj) {
var newObj = {};
for(p in obj) { newObj[obj[p].id] = obj[p]; }
return newObj;
}
var objB = transform(objA);
console.log(objB);
You could use Object.entries and iterate through the key-value pairs with .reduce
const data = {
0: { id: "id3", name: "Capitan America", job: "superHero" },
1: { id: "id4", name: "Spider-man", job: "Pro footballer" },
}
const res = Object.entries(data).reduce(
(acc, el) => ({ ...acc, [el[1].id]: el[1] }),
{}
)
console.log(res)
Map the array to pairs of [id, object], and then convert to an object using Object.fromEntries():
const arr = [
{ id: 'id3', name: 'Capitan America', job: 'superHero' },
{ id: 'id4', name: 'Spider-man', job: 'Pro footballer' }
]
const result = Object.fromEntries(arr.map(o => [o.id, o]))
console.log(result)
I created a form to get some info from User, and I want to move some of their info into a nested object. the reason why is to better organize my data later in front-end.
As a simple example, how to create the following "newInfo" out of "oldInfo" in JavaScript?
oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
newInfo = {
name: 'John',
Age: '32',
friends: {
friend1: 'Michael',
friend2: 'peter',
},
};
I'm sure this must be a repeated and simple topic, but I couldn't find any as I didn't know what keyword to search for.
You could explicitly assign it
const oldInfo = {
name: "John",
Age: "32",
friend1: "Michael",
friend2: "Peter",
}
const newInfo = {
name: oldInfo.name,
Age: oldInfo.Age,
friends: {
friend1: oldInfo.friend1,
friend2: oldInfo.friend2,
},
}
console.log(newInfo)
You can do this easily with spread operator:
const { name, Age, ...friends } = oldInfo;
newInfo = { name, Age, friends };
It simply extracts all fields except name and age as friends.
Example:
const oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
const { name, Age, ...friends } = oldInfo;
const newInfo = { name, Age, friends };
console.log(newInfo);
If you have a dynamic number of friend: name key-value pairs and other properties that shouldn't be nested into friends then you can use Object.entries and reduce:
const oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
const newInfo = Object.entries(oldInfo).reduce((acc, [k, v]) => {
if(k.startsWith('friend')) {
acc.friends ? acc.friends[k] = v : acc.friends = {[k]: v};
} else {
acc[k] = v;
}
return acc;
},{});
console.log(newInfo);
I have the following sample array:
mainArray = [
{id: 15475, name: 'Ali', gender: 'Male', addresses: [
{address1: 'Lebanon'},
{address2: 'USA'}]
},
{id: 15475, name: 'Emily', gender: 'Female', addresses: [
{address1: 'UK'},
{address2: 'France'}]
},
];
I need to transform it into something like:
mainArray = [
{id: 15475, name: 'Ali', gender: 'Male', addresses: 'Lebanon, USA'},
{id: 15475, name: 'Emily', gender: 'Female', addresses: 'UK, France }
];
In this case, I added all nested arrays inside a an element of the mainArray into one single string value.
What I've done so far is, I extracted the key names of the mainArray:
extractedIndexes = ['id', 'name', 'gender', 'addresses'];
And made a loop to check the type of each element inside of the mainArray, and if it's an object I will concat the values of the nested array into one single string:
for (const idx of this.extractedIndexes) {
console.log(idx)
this.mainArray.forEach((elem) => {
let newItem = '';
if (typeof (elem[idx]) == 'object') {
elem[idx] = Object.keys(elem[idx]).forEach((key) => {
console.log(elem[idx][key])
// Add it to the field
})
console.log(elem[idx])
}
})
}
console.log(this.mainArray)
This line console.log(elem[idx][key]) is always returning the following:
{address1: "Lebanon"}
{address2: "USA"}
{address1: "UK"}
{address2: "France"}
Take note that here address1 and address2 are simple examples, as my real data contain multiple nested arrays, and each one have different new key names.
I tried to do the following:
if (typeof (elem[idx]) == 'object') {
elem[idx] = elem[idx].toString().split(',')
// Add it to the field
console.log(elem[idx])
}
But it returned [Object, Object].
So how can I transform a nested array into single concatenated string value?
Here is a stackblitz.
Just use map and use Object.values to get values from object:
mainArray.map(({addresses, ...rest}) => ({...rest, addresses:
addresses.map(s => Object.values(s)).join(', ')}) );
An example:
let mainArray = [
{id: 15475, name: 'Ali', gender: 'Male', addresses: [
{address1: 'Lebanon'},
{address2: 'USA'}]
},
{id: 15475, name: 'Emily', gender: 'Female', addresses: [
{address1: 'UK'},
{address2: 'France'}]
},
];
const result = mainArray.map(({addresses, ...rest}) => ({...rest, addresses: addresses.map(s => Object.values(s)).join(', ')}) );
console.log(result);
If you don't know whether the key is array, then you can try to use reduce method:
const result = mainArray.reduce((a, c)=> {
for (const key in c) {
if (Array.isArray(c[key]))
c[key] = c[key].map(s => Object.values(s)).join(', ');
}
a.push(c);
return a;
},[])
console.log(result);
An example:
let mainArray = [
{id: 15475, name: 'Ali', gender: 'Male', addresses: [
{address1: 'Lebanon'},
{address2: 'USA'}]
},
{id: 15475, name: 'Emily', gender: 'Female', addresses: [
{address1: 'UK'},
{address2: 'France'}]
},
];
const result = mainArray.reduce((a, c)=> {
for (const key in c) {
if (Array.isArray(c[key]))
c[key] = c[key].map(s => Object.values(s)).join(', ');
}
a.push(c);
return a;
},[])
console.log(result);
You could use recursive function to get addresses that will work on any nested structure and get the value if the key starts with address and value is not an object.
const data =[{"id":15475,"name":"Ali","gender":"Male","addresses":[{"address1":"Lebanon"},{"address2":"USA"}]},{"id":15475,"name":"Emily","gender":"Female","addresses":[{"address1":"UK"},{"address2":"France"}]}]
const flat = (data, prev = '') => {
let sep = prev ? ', ' : ''
let result = '';
for (let i in data) {
if (typeof data[i] == 'object') {
result += flat(data[i], prev + result)
} else if (i.startsWith('address')) {
result += sep + data[i]
}
}
return result
}
const result = data.map(({
addresses,
...rest
}) =>
({ ...rest,
addresses: flat(addresses)
}))
console.log(result)
{id: 15475, name: 'Ali', gender: 'Male', addresses: [
{address1: 'Lebanon'},
{address2: 'USA'}]
},
{id: 15475, name: 'Emily', gender: 'Female', addresses: [
{address1: 'UK'},
{address2: 'France'}]
},
];<br>
function toString(arro) {
return arro.reduce(
(acc, rec) => {
return [...acc, Object.values(rec)]
}, []
).join(',')
}
const res = mainArray.map(
it => {
return Object.keys(it).reduce(
(acc, item) => {
if (typeof it[item] === 'object') {
return {...acc, [item]: toString(it[item])}
}
return {...acc, [item]: it[item]}
}, {}
)
}
)```
I would like to fuse Array.filter() function to remove duplicate objects
I am able to achieve in the case of string or integer arrays. But I am not able to achieve the same with array of objects as in the second case of names
const names = ['John', 'Paul', 'George', 'Ringo', 'John'];
let x = names => names.filter((v, i, arr) => arr.indexOf(v) === i);
console.log(x(names)); //[ 'John', 'Paul', 'George', 'Ringo' ]
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
// returns the same original array
Could you please help?
Using Array#reduce() and a Map accumulator then spread the values() of the Map into array
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
const unique = [... names.reduce((a,c)=>(a.set(c.name,c)),new Map).values()]
console.log(unique)
Use Array.reduce and Object.values
Iterate over the array and create an object with key as name and value as object from array. In case of objects with same name, the value will be overwritten in resultant object. Finally use Object.values to collect all the unique objects.
const names = [{ name: "John" },{ name: "Paul" },{ name: "George" },{ name: "Ringo" },{ name: "John" } ];
let result = Object.values(names.reduce((a,c) => Object.assign(a, {[c.name]:c}),{}));
console.log(result);
For tweaking - Plunker
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" }
];
/* unique => Filter: Remove all duplicate items from an array. Works with plain objects as well, since we stringify each array item.
* #type public Function
* #name unique
* #return Function( item )
* #notes
*/
const unique = () => {
const seen = {};
return item => {
const json = JSON.stringify( item );
return seen.hasOwnProperty( json )
? false
: ( seen[ json ] = true );
};
};
const result = names.filter( unique() );
console.log( result );
You could use lodash's _uniqBy for this:
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
const result = _uniqBy(names, 'name');
This can be done with the help of Sets as well
var names = [{ name: "John" },{ name: "Paul" },{ name: "George" },{ name: "Ringo" },{ name: "John" } ];
var result = Array.from(
names.reduce((s, d) => s.add(d.name), new Set)
, d => ({ name: d })
)
console.log(result)
Keith had a great suggestion to use findIndex with filter instead of indexOf. Object literals are always unique references, so we cannot compare them. We can however compare the name keys between the objects. We can do this with the aforementioned functions.
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" }
];
console.log(names.filter(({name1}, i, a) => {
return i == a.findIndex(({name2}) => {
return name1 == name2;
});
});
const names = ['John', 'Paul', 'George', 'Ringo', 'John'];
function removeDups(names) {
let unique = {};
names.forEach(function(i) {
if(!unique[i]) {
unique[i] = true;
}
});
return Object.keys(unique);
}
removeDups(names); //'John', 'Paul', 'George', 'Ringo'