Given an array of objects all with the same property names, with javascript how would you create a new object made up of key:value pairs that are found in all the objects of the array?
For example, given:
[
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
]
Result:
{
b: 'bar',
c: 'zip'
}
Start with all the elements of the first item (cloned, because we don't want to change the original data), then remove any key-value pairs that do not show up in the subsequent items:
const data = [
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
];
const [first, ...rest] = data;
const result = rest.reduce((a, e) => {
Object.keys(a).forEach(k => {
if (!k in e || e[k] !== a[k]) {
delete a[k];
}
});
return a;
}, {...first});
console.log(result);
Just compare each value in the first object with every other object.
const [first, ...others] = [
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
];
for (const [key, value] of Object.entries(first)) {
for (const object of others) {
if (object[key] !== value) {
delete first[key];
}
}
}
console.log(first);
Related
I have an array of objects that has a nested array of objects in it. So the array looks something like:
const list = [
{
A: "a1",
B: "b1",
C: [
{
A: "a22",
B: "b12"
},
{
A: "a11",
B: "b11"
},
{
A: "a10",
B: "b10"
}
]
},
{
A: "a2",
B: "b2",
C: [
{
A: "a10",
B: "b10"
},
{
A: "a01",
B: "b01"
}
]
},
{
A: "a0",
B: "b0",
C: [
{
A: "a22",
B: "b22"
},
{
A: "a21",
B: "b21"
},
{
A: "a20",
B: "b20"
}
]
}
];
As can be seen I have an array of objects and each object as one or more fields that is also an array of objects. I can sort the array of objects based on one of the keys and it works just fine. What I want to do is sort by one of the keys in the nested array. For example sorting on C.A would yield something like (expected):
[
{
A: "a0",
B: "b0",
C: [
{
A: "a22",
B: "b22"
},
{
A: "a21",
B: "b21"
},
{
A: "a20",
B: "b20"
}
]
},
{
A: "a1",
B: "b1",
C: [
{
A: "a12",
B: "b12"
},
{
A: "a11",
B: "b11"
},
{
A: "a10",
B: "b10"
}
]
},
{
A: "a2",
B: "b2",
C: [
{
A: "a10",
B: "b10"
},
{
A: "a01",
B: "b01"
}
}
];
Ideas?
The way to get one's head clear on such things is to factor out the sort functions to explicitly state the objective, like this (I think I understand the objective)...
// sort a and b by the smallest value of A in their C arrays
const myCompare = (a, b) => {
return a.minAinC.localeCompare(b.minAinC);
};
// get the lexically smallest value of A in an object's C array
const minAinC = obj => {
const minC = obj.C.reduce((acc, o) => acc.A.localeCompare(o.A) > 0 ? o : acc, obj.C[0])
return minC.A;
};
// preprocess the outer array and cache a minAinC value on each, making the next sort efficient (optional)
const data = getData()
const readyToSort = data.map(o => ({ ...o, minAinC: minAinC(o) }));
const sorted = readyToSort.sort(myCompare)
console.log(sorted)
function getData() {
return [{
A: "a1",
B: "b1",
C: [{
A: "a22",
B: "b12"
},
{
A: "a11",
B: "b11"
},
{
A: "a10",
B: "b10"
}
]
},
{
A: "a2",
B: "b2",
C: [{
A: "a10",
B: "b10"
},
{
A: "a01",
B: "b01"
}
]
},
{
A: "a0",
B: "b0",
C: [{
A: "a22",
B: "b22"
},
{
A: "a21",
B: "b21"
},
{
A: "a20",
B: "b20"
}
]
}
];
}
I have an array of the form:
const obj1 = {
key1: {
a: 'x',
b: 2
},
key2: {
a: 'y',
b: 4
},
key3: {
a: 'z',
b: 3
}
}
I want to create a new object obj2 of the form:
const obj2 = {
key1: 'x',
key2: 'y',
key3: 'z',
}
I could do it using for...in loop, but I need a one-liner.
const obj2 = {};
for (let key in obj1) {
obj2[key] = obj1[key].a
}
Please tell me how do I create a one-liner for this.
You can take Object.entries and then use reduce:
const obj1 = { key1: { a: 'x', b: 2 }, key2: { a: 'y', b: 4 }, key3: { a: 'z', b: 3 }};
const result = Object.entries(obj1).reduce((a,[key, val])=>(a[key]=val.a,a),{});
console.log(result);
You can map the keys of the object and return objects for each element containing the desired structure. Then you can spread the results into a newly assigned object.
const obj1 = {
key1: {
a: 'x',
b: 2
},
key2: {
a: 'y',
b: 4
},
key3: {
a: 'z',
b: 3
}
};
console.log(Object.assign(...Object.keys(obj1).map((k) => ({ [k]: obj1[k].a }))));
You could map the entries with a destructuring for a new object.
const
object = { key1: { a: 'x', b: 2 }, key2: { a: 'y', b: 4 }, key3: { a: 'z', b: 3 } },
result = Object.fromEntries(Object.entries(object).map(([k, { a }]) => [k, a]));
console.log(result);
How to achieve below output?
const arr = [{ a: 1 }, { a: 2 }, { a: 3 }];
Required Output: { a: 1 , a: 2 , a: 3 }
The Object.assign overrides the key value and reduces to below output.
Object.assign({}, ...arr); // Output: {a:3}
This is what I should have written on original post -
Array of Object: [{ a: { a: 1 }, b: { a: 2 }, c: { a: 3 } }]
Single Object: { a: { a: 1 }, b: { a: 2 }, c: { a: 3 } }
I was able to achieve it by using below code.
const obj = arr.reduce((accum, value) => {
return { ...accum, ...value }
}, {});
I'm parsing a csv fils to json with node-csvtojson and I got a JSONarray with the following code
csv({delimiter: ';'}).fromFile(path).then((jsonObj)=>{
data = jsonObj;
console.log(jsonObj);
})
with a csv like
a,b,c
A,B,C
1,2,3
1,B,C
I have got
[
{
a: A,
b: B,
c: C,
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C
}
]
But I want to find every object who has the element a === 1 and I want to have all the content of the object,
like this:
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C,
}
But I 'm struggling to do that, I have tried with array.filter but without success then I have tried to do this with array.map but I got lost on how to do.
Do you have any idea on or I could do that ?
Than you
Use Array.filter like so:
const data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(({ a }) => a == 1));
If you want this to work with old browsers, here's an ES5-compliant version:
var data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(function(obj) {
return obj.a == 1
}));
Simple use Array.filter to filter through the object array and select the one having property a === 1
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const filteredArr = arr.filter(obj => obj.a === 1);
console.log(filteredArr);
Using Array.reduce you can do the same thing:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const redArr = arr.reduce((acc, obj) => {
return acc = obj.a === 1 ? acc.concat(obj) : acc;
}, []);
console.log(redArr);
Using Array.map for this problem is not the right approach, although it is possible:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const mapArr = arr.map(obj => obj.a === 1 ? obj : undefined).filter(obj => obj); //hack to remove undefined elements
console.log(mapArr);
console.log([{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
].filter(o => o.a === 1))
Try this :
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
var res = arr.filter(obj => obj.a === 1);
console.log(res);
What's an elegent way - purely functional, ideally - to transform (reduce?) this array:
var in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
Into this:
var out = [
{ a: 1, x: 'foo', y: 'goo' },
{ a: 2, x: 'hoo', y: 'joo' }
]
The logic is that all elements should be joined based on their a property, and all b and c properties denote key/value pairs respectively that should be merged into the single object based on their shared a value.
You can use a hash object, and reduce to wrap the hashing like this:
const arr = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
let result = Object.values( // the result is the values of the hash object
arr.reduce((hash, o) => { // hash is a hash object that make it easier to group the result
hash[o.a] = hash[o.a] || {a: o.a}; // if there is no object in the hash that have the value of the key a equal to o.a, then create a new one
hash[o.a][o.b] = o.c; // set the value of the key stored in o.b to o.c
return hash;
}, {})
);
console.log(result);
You could use a closure with a Map
var input = [{ a: 1, b: 'x', c: 'foo' }, { a: 1, b: 'y', c: 'goo' }, { a: 2, b: 'x', c: 'hoo' }, { a: 2, b: 'y', c: 'joo' }],
output = input.reduce((map => (r, o) => (!map.has(o.a) && map.set(o.a, r[r.push({ a: o.a }) - 1]), map.get(o.a)[o.b] = o.c, r))(new Map), []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use forEach and Object.assign to group by a and then map to return object values.
var data = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
var r = {}
data.forEach(e => r[e.a] = Object.assign((r[e.a] || {}), {a: e.a, [e.b]: e.c}))
r = Object.keys(r).map(e => r[e])
console.log(r)
I like provided answers, but here is my attempt. I believe it's more readable, but it uses Object.assign and Object.values
const input = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
const map = input.reduce((acc, obj) => {
const [a, key, value] = Object.values(obj)
const newObj = {a, [key]: value}
if (acc[a]) {
Object.assign(acc[a], newObj)
} else {
acc[a] = newObj
}
return acc
}, {})
console.log(Object.values(map))
Not sure if approach is elegant or functional, though returns expected result using for..of loops, Array.prototype.some() and Object.assign()
function props(array, key, prop1, prop2) {
let arr = [];
for (let obj of array) {
let o = {};
for (let {[key]:_key, [prop1]:_prop1, [prop2]:_prop2} of [obj]) {
o[_prop1] = _prop2;
o[key] = _key;
}
if (!arr.some(p => p[key] === o[key])) arr.push(o);
for (let prop of arr) {
if (prop[key] == o[key]) {
prop = Object.assign(prop, o)
}
}
}
return arr
}
var _in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
console.log(props(_in, "a", "b", "c"));