Get an element object of an array from a key name - javascript

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);

Related

return object in an array with the most props

Say I have an array of objects like this:
const arr = [
{ a: 1, b: 2, c: 3, d: 4 },
{ a: 1 },
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2 }
];
How can I return the object with the most properties/keys? Preferably using in an efficient and terse manner using higher order functions.
You could assign to a single object.
const
array = [{ a: 1, b: 2, c: 3, d: 4 }, { a: 1 }, { a: 1, b: 2, c: 3 }, { a: 1, b: 2 }],
object = Object.assign({}, ...array);
console.log(object);
If you have different values, you could reduce the array.
const
array = [{ a: 1, b: 2, c: 3, d: 4 }, { a: 1 }, { a: 1, b: 2, c: 3 }, { a: 1, b: 2 }],
object = array.reduce((a, b) => Object.keys(a).length > Object.keys(b).length
? a
: b
);
console.log(object);
You can get the number of keys from an object by calling Object.keys(obj) and then checking it's length property.
With that, you could reduce the array by checking each pair of objects and return the one with the most keys as a one liner:
const biggestObject =
arr.reduce((a, b) => Object.keys(a).length > Object.keys(b).length ? a : b);

Add new property to object collection based on condition with lodash

I have an array of objects as such:
var data = [{ a: 1 },
{ a: 1 },
{ a: 2 },
{ a: 2 }];
How can I create, with lodash, a new array just like data but for which we added a new property b: 1 to each object that has the property a equal to 1?
The new array should be like this:
var newdata = [{ a: 1, b: 1 },
{ a: 1, b: 1 },
{ a: 2 },
{ a: 2 }];
I guess we could combine both _.assign and _.filer but I'm not sure how.
You can do this with lodash via either _.defaults or _.assign / _.assignIn / _.extend:
var data = [{ a: 1 },{ a: 1 },{ a: 2 },{ a: 2 }];
console.log(_.map(data, x => x.a==1 ? _.defaults(x, {b: 1}) : x))
console.log(_.map(data, x => x.a==1 ? _.assign(x, {b: 1}) : x))
console.log(_.map(data, x => x.a==1 ? _.assignIn(x, {b: 1}) : x))
console.log(_.map(data, x => x.a==1 ? _.extend(x, {b: 1}) : x))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
You could map the array and use a new property if the condition is true.
var data = [{ a: 1 }, { a: 1 }, { a: 2 }, { a: 2 }],
newData = data.map(o => Object.assign({}, o, o.a === 1 && { b: 2 }));
console.log(newData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you're happy with vanilla Javascript, this here works:
var data = [{ a: 1 },
{ a: 1 },
{ a: 2 },
{ a: 2 }];
var newData = [];
newData = data.reduce((acc, el) => {
return el.a === 1 ? acc.concat({a: el.a, b: 1}) : acc.concat(el);
}, []);
console.log(newData);
// expected output: [{a: 1, b: 1},
// {a: 1, b: 1},
// {a: 2},
// {a: 2}]
You can generate a function with lodash by applying _.cond() to _.map() with _.partialRight.
Use _.matches() to detect if the object has a: 1 property, and _.assign() { b: 1 } if it does.
When a is not 1, use _.stubTrue() to always return the original object via _.identity():
var func = _.partialRight(_.map, _.cond([
[_.matches({ 'a': 1 }), o => _.assign({}, o, { b: 2 })],
[_.stubTrue, _.identity]
]));
var data = [{ a: 1 },{ a: 1 },{ a: 2 },{ a: 2 }];
const result = func(data);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Create new object based on filtered keys

Suppose I have an array of strings that represent keys such as ['a', 'b', 'd'], and an existing object such as...
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
}
Is there a method of creating a new object that is a filtered version of obj based on the keys in the array such that...
const updated = {
a: 1,
b: 2,
d: 4
}
using the Object.assign() function?
I know it works with a function such as...
function createNew(o, keys) {
const updated = {}
Object.keys(o).forEach(k => {
if (keys.includes(k)) updated[k] = o[k]
})
return updated
}
but I'm looking for a solution with Object.assign()
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
const desiredKeys = ['a', 'c', 'd'];
const result = desiredKeys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
console.log(result);

Elegant array transformation in Javascript

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"));

Return an Array of Arrays containing objects that share a common value in a property

Say I have an array of 3 objects like this:
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
},
{
a: 2,
b: 3,
c: 3
}
]
I would like to return an array of arrays containing the objects that share a common value for the property b. So the resulting array would contain only one array containing 2 objects like this:
[
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
}
]
]
How would I do this?
You could do this with map and filter
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}];
var check = data.map(e => {return e.b});
var result = [data.filter(e => { return check.indexOf(e.b) != check.lastIndexOf(e.b)})];
console.log(result)
To group multiple objects in separate arrays with same b values you can use map and forEach
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}, {"a":3,"b":7,"c":6},{"a":2,"b":7,"c":3}], result = [];
var check = data.map(e => {return e.b});
data.forEach(function(e) {
if(check.indexOf(e.b) != check.lastIndexOf(e.b) && !this[e.b]) {
this[e.b] = [];
result.push(this[e.b]);
}
(this[e.b] || []).push(e);
}, {});
console.log(result)
This proposal uses a single loop with Array#forEach but without Array#indexOf.
var array = [{ a: 4, b: 5, c: 4 }, { a: 3, b: 5, c: 6 }, { a: 2, b: 3, c: 3 }],
grouped = [];
array.forEach(function (a) {
this[a.b] = this[a.b] || [];
this[a.b].push(a);
this[a.b].length === 2 && grouped.push(this[a.b]);
}, Object.create(null));
console.log(grouped);
You can create a function that accepts fulfillment criteria and will return as many nested arrays as rules passed.
Let's say you have an array of objects, arr.
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
And you want to return an array with with nested arrays that fulfill a particular requirement, let's say you want objects with an a:1 and b:2.
You can create a function that loops through your rules and creates a nested array with the objects that fulfill each rule.
For example:
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
function makeNestedArrays() {
var rules = [].slice.call(arguments);
return rules.reduce(function(acc, fn) {
var nestedArr = [];
arr.forEach(function(obj) {
if (fn(obj)) {
nestedArr.push(obj);
}
});
// only push nested array
// if there are matches
if (nestedArr.length) {
acc.push(nestedArr);
}
return acc;
}, []);
}
var result = makeNestedArrays(
function(obj) { return obj.a === 1; },
function(obj) { return obj.b === 2; }
);
console.log(result);
This allows you to pass as many "rules" as you want, and will create a nested array for each rule so long as there is at least one match.
You could use a Map to group them, this should work with any kind of value (just be sure the equality rules check out):
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
console.log(...(result.values()));
If you'd need to filter out the groups of 1:
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
result = [...result.values()].filter(a => a.length > 1);
console.log(result);

Categories

Resources