Lodash Not executing the nested method, - javascript

given this array var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}].
I want to iterate through each item in the array and omit the key c and it's value using lodash.
here is the method I tried
_.each(array, function (obj) {
return _.omit(obj, ['a']);
});
Expected Output should be // [{b: 2, c: 3}, {b: 4, c: 4} ]
but lodash returns the original array// [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]

Instead of forEach() to return new modified array you should use map(), also first parameter is array.
var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]
var result = _.map(array, function (obj) {
return _.omit(obj, ['a']);
});
console.log(JSON.stringify(result, 0, 4))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

A probably-not-the-lo-dash-iest way of handling it (assuming you actually want to omit a):
_.each(lnkn, function (obj) {
var returnObj = {};
for (prop in obj) {
if (obj.hasOwnProperty(prop) {
if (prop !== 'a') {
returnObj[prop] = obj[prop];
}
}
}
return returnObj;
});

_.forEach is supposed to return the original array. You re looking for _.map.
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
const result = _.map(array, obj => _.omit(obj, 'a'));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Or you can modify the objects in place:
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
_.forEach(array, obj => {
delete obj.a;
});
console.log(array);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Related

I want to create an object with the key as a property from the object and value as an array of objects matching the key (javascript)

I have a given object to iterate and create another object in the below format (newObj)
Given object:
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
Expected object:
newObj = {
1: [{a: 1, b: 232}, {a: 1, b: 2}, {a: 1, b: 256}],
2: [{a: 2, b: 3}],
3: [{a: 3, b: 4}]
}
Code:
let newObj = {};
obj.forEach(element => {
if (newObj[element.a]) {
let key = element.a;
newObj[key] = newObj[key].push(element);
}
newObj[element.a] = [element];
});
console.log(newObj);
We create a result object, loop through every object in obj array, if we don't have the object a key in the result object, we add him (a: []), and after that we push the entire object to result[a] array
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
let result = {};
for(const {a, b} of obj) {
if(!result[a]) result[a] = []
result[a].push({a, b})
}
console.log(result)
To address your updated code snippet, you need to only create a new array for a given key if they key does not exist.
let obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
let newObj = {};
obj.forEach(element => {
let key = element.a;
if (!newObj[key]) {
newObj[key] = []; // Only initialize if undefined/null
}
newObj[key].push(element); // Always push
});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
A more modern approach would be to simply bin them by the a key by reducing and spreading.
const obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
const newObj = obj.reduce((acc, o) => ({
...acc,
[o.a]: [...(acc[o.a] ?? []), o]
}), {});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can use reduce for that
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
const newObj = obj.reduce((res, {a, b}) => {
return {
...res,
[a] : [...(res[a] || []), {a, b}]
}
}, {})
console.log(newObj)

Cumulative sum of specific keys with array output using reduce

Say I have the following array:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
I would like to compute the cumulative sum of each key, but I would also like the output to be an array of the same length with the cumulative values at each step. The final result should be:
[{a: 1, b: 2}, {a: 3, b: 6}, {a: 11, b: 5}]
My issue is that I am not able to obtain the array as desired. I only get the final object with this:
let result = arr.reduce((accumulator, element) => {
if(accumulator.length === 0) {
accumulator = element
} else {
for(let i in element){
accumulator[i] = accumulator[i] + element[i]
}
}
return accumulator
}, [])
console.log(result); // {a: 11, b: 5}
What you're after sounds like the scan() higher-order function (borrowing the idea from ramda.js), which allows you to return an accumulated result for each element within your array. The scan method is similar to how the .reduce() method behaves, except that it returns the accumulator for each element. You can build the scan() function yourself like so:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}];
const scan = ([x, ...xs], fn) => xs.reduce((acc, elem) => {
return [...acc, fn(acc.at(-1), elem)];
}, xs.length ? [x] : []);
const res = scan(arr, (x, y) => ({a: x.a+y.a, b: x.b+y.b}));
console.log(res);
You might consider further improvements such as providing an initial value to the scan method (similar to how reduce accepts one). Also, if you need better browser support the .at() method currently has limited browser support, so you may instead consider creating your own at() function:
const at = (arr, idx) => idx >= 0 ? arr[idx] : arr[arr.length + idx];
You can easily achieve the result using reduce as
let arr = [
{ a: 1, b: 2 },
{ a: 2, b: 4 },
{ a: 8, b: -1 },
];
const result = arr.reduce((acc, curr, i) => {
if (i === 0) acc.push(curr);
else {
const last = acc[i - 1];
const newObj = {};
Object.keys(curr).forEach((k) => (newObj[k] = curr[k] + last[k]));
acc.push(newObj);
}
return acc;
}, []);
console.log(result);
Something like this:
const arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
const result = arr.reduce((accumulator, element, index) => {
if(accumulator.length === 0) {
accumulator.push(element)
} else {
const sum = {};
for(let i in element) {
sum[i] = element[i] + (accumulator[index - 1][i] || 0)
}
accumulator.push(sum)
}
return accumulator
}, [])
console.log(result);
Another option is keep sum result using a Map, it helps if keys in elements of the array are not always same.
const arr = [{a: 1, b: 2}, {a: 2}, {a: 8, b: -1}];
const map = new Map();
const result = arr.map((element) => {
const sum = {};
for (let i in element) {
sum[i]= element[i] + (map.get(i) || 0);
map.set(i, sum[i]);
}
return sum;
});
console.log(result);
Here is a bit more concise reduce, probably not as readable as a consequence...
array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
let array = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
let culm = array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
console.log(culm)
Given:
const xs =
[ {a: 1, b: 2}
, {a: 2, b: 4}
, {a: 8, b: -1}];
Define a function sum such as:
const sum = ([head, ...tail]) =>
tail.reduce((x, y) =>
({a: (x.a+y.a), b: (x.b+y.b)}), head);
sum(xs);
//=> {a: 11, b: 5}
Then apply that function in a map on larger slices of xs:
xs.map((_, i, arr) => sum(arr.slice(0, i+1)));
//=> [ {a: 1, b: 2}
//=> , {a: 3, b: 6}
//=> , {a: 11, b: 5}]

Array of properties of objects in an array

Given the array of objects:
data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}]
How can I get an array of only a elements of the objects? Something like this:
a = [1, 4, 7]
Is it possible without iterating through the objects?
This is easy to achieve with .map()
var data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}];
var a = data.map(obj => obj.a);
console.log(a);
You can also try this:
var result = data.reduce(function(result, obj) {
return result.concat(obj.a);
}, []);
There are several methods.
You should look into Array.map() or the powerful Lodash library.
let aElements = data.map(o => o.a);
Using functional programming(map higher-order function):
var a = data.map(function(obj){return obj.a});
or the same in es6:
let a = data.map(obj=>obj.a);
But, nevertheless, technically Array.prototype.map iterates.

Filtering an object by property in Ramda.js

I'm new to using Ramda.js and am wondering how I can filter an object based on specified properties.
Looking at R.filter, it seems that _.filter only passes the object value and not the property. For instance, the example given in the REPL:
var isEven = (n, prop) => {
console.log(typeof prop);
// =>
// undefined
// undefined
// undefined
// undefined
return n % 2 === 0;
}
R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
If I have the following object:
const obj = {a: 1, b: 2, c: 3};
My desired result would be:
const filterProp = (x) => /* some filter fn */;
filterProp('b')(obj);
// => {a: 1, c: 3};
How can I use Ramda to filter the properties of an object?
After digging through the Ramda docs, I found R.omit which satisfies my particular use case.
const obj = {a: 1, b: 2, c: 3};
R.omit(['b'], obj);
// => {a: 1, c: 3};
Use the pickBy method which allows you to filter a collection based on the keys.
const obj = {a: 1, b: 2, c: 3};
var predicate = (val, key) => key !== 'b';
R.pickBy(predicate, obj);
// => {a: 1, c: 3}

Most concise way of producing an object from another object and an array of keys to keep?

Is there a lodash function, or possibly a combination of two, that can take an object and array of keys to keep to output the object reduced to just those keys?
{a: 1, b: 2, c: 3, d: 4} and ['a', 'c'] => {a: 1, c: 3}
https://lodash.com/docs#pick
var obj = {a: 1, b: 2, c: 3, d: 4};
var keys = ['a', 'c'];
var filtered = _.pick(obj, keys);
document.body.innerHTML = '<pre>' + JSON.stringify(filtered, null, ' ') + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
You can do this. It's not lodash but it's fairly quick in assembling the object.
function reduce(obj, keys)
{
var newObj = {};
keys.forEach(function(element)
{
newObj[element] = obj[element];
});
return newObj;
}
var myObj = {a: 1, b: 2, c: 3, d: 4};
var reducedObj = reduce(myObj, ["a", "c"]);

Categories