lodash: mapping array to object - javascript

Is there a built-in lodash function to take this:
var params = [
{ name: 'foo', input: 'bar' },
{ name: 'baz', input: 'zle' }
];
And output this:
var output = {
foo: 'bar',
baz: 'zle'
};
Right now I'm just using Array.prototype.reduce():
function toHash(array, keyName, valueName) {
return array.reduce(function(dictionary, next) {
dictionary[next[keyName]] = next[valueName];
return dictionary;
}, {});
}
toHash(params, 'name', 'input');
Wondering if there's a lodash short-cut.

Another way with lodash 4.17.2
_.chain(params)
.keyBy('name')
.mapValues('input')
.value();
or
_.mapValues(_.keyBy(params, 'name'), 'input')
or with _.reduce
_.reduce(
params,
(acc, { name, input }) => ({ ...acc, [name]: input }),
{}
)

You should be using _.keyBy to easily convert an array to an object.
Docs here
Example usage below:
var params = [
{ name: 'foo', input: 'bar' },
{ name: 'baz', input: 'zle' }
];
console.log(_.keyBy(params, 'name'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
If required, you can manipulate the array before using _.keyBy or the object after using _.keyBy to get the exact desired result.

Yep it is here, using _.reduce
var params = [
{ name: 'foo', input: 'bar' },
{ name: 'baz', input: 'zle' }
];
_.reduce(params , function(obj,param) {
obj[param.name] = param.input
return obj;
}, {});

This seems like a job for Object.assign:
const output = Object.assign({}, ...params.map(p => ({[p.name]: p.input})));
Edited to wrap as a function similar to OP's, this would be:
const toHash = (array, keyName, valueName) =>
Object.assign({}, ...array.map(o => ({[o[keyName]]: o[valueName]})));
(Thanks to Ben Steward, good thinking...)

This is probably more verbose than you want, but you're asking for a slightly complex operation so actual code might be involved (the horror).
My recommendation, with zipObject that's pretty logical:
_.zipObject(_.map(params, 'name'), _.map(params, 'input'));
Another option, more hacky, using fromPairs:
_.fromPairs(_.map(params, function(val) { return [val['name'], val['input']));
The anonymous function shows the hackiness -- I don't believe JS guarantees order of elements in object iteration, so callling .values() won't do.

You can use one liner javascript with array reduce method and ES6 destructuring to convert array of key value pairs to object.
arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});

Another way with lodash
creating pairs, and then either construct a object or ES6 Map easily
_(params).map(v=>[v.name, v.input]).fromPairs().value()
or
_.fromPairs(params.map(v=>[v.name, v.input]))
Here is a working example
var params = [
{ name: 'foo', input: 'bar' },
{ name: 'baz', input: 'zle' }
];
var obj = _(params).map(v=>[v.name, v.input]).fromPairs().value();
console.log(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

It can also solve without using any lodash function like this:
let paramsVal = [
{ name: 'foo', input: 'bar' },
{ name: 'baz', input: 'zle' }
];
let output = {};
paramsVal.forEach(({name, input})=>{
output[name] = input;
})
console.log(output);

Related

What is the most elegant way to remove an array of properties from an object immutably in JavaScript?

Not sure if I'm trying to accomplish too much here in an elegant way, but let's say I have an object as follows:
const obj = { foo: 'bar', prop: 'str', hi: 'hello' };
And then I have an array of properties I want to remove from that object:
const keys = ['prop', 'hi'];
I'm looking for the best way I can immutably get an output of:
{ foo: 'bar' }
I was looking into using destructuring assignments but I couldn't figure out how to make it work with an array of properties unless it has a static length:
({ [keys[0]]: value, [keys[1]]: value, ...output }) = o;
Maybe there's an alternative way to do the above line but using mapping?
Thanks!
You could iterate the array and use delete to delete each matching keys.
To make a copy of the object you have you could use the spread operator
const keys = ['prop', 'hi'];
const obj = { foo: 'bar', prop: 'str', hi: 'hello' };
const newobj={...obj}
keys.forEach(o=> delete newobj[o])
console.log(obj)
console.log(newobj)
Here is another approach using Object.fromEntries and filter, some
const keys = ['prop', 'hi'];
const obj = { foo: 'bar', prop: 'str', hi: 'hello' };
res=Object.fromEntries(Object.entries(obj).filter(o=>!keys.some(k=>o[0]==k)))
console.log(res)
console.log(obj)
I would use a combination of the Object.fromEntries, Object.entries, and the Array .filter methods. Then this operation becomes quite straightforward:
function removeKeysFromObj(obj, keys) {
return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key)));
}
const obj = { foo: 'bar', prop: 'str', hi: 'hello' };
const keys = ['prop', 'hi'];
const newObj = removeKeysFromObj(obj, keys);
console.log("New object:", newObj);
// And note the original is unmodified:
console.log("Original object:", obj);
One way to approach this is to think in the reverse way: map over the keys in the original object and keep the ones not in the list:
function removeKeys(obj, keys) {
return Object.keys(obj)
.filter(k => !keys.includes(k))
.reduce((newObj, k) => {
newObj[k] = obj[k];
return newObj
}, {});
I'd do it like this.
const obj = { foo: 'bar', prop: 'str', hi: 'hello' };
const keys = ['prop', 'hi'];
let result = Object.keys(obj).reduce((current, item) => (keys.includes(item) || (current[item] = obj[item]), current), {});
console.log(result);

Assign multiple keys a certain value using ramda.js assocPath?

I am quite new to JS and ramda.js. Let's say i have an object consisting of empty objects like this:
obj = { 1: { }, 2: { }, 3: { } }
and array consisting of chosen keys of the obj .
arr = ['1', '2']
What i need is to create a certain key-value pair, for example a: 'value', inside of the key objects chosen via arr, so the result would look like this:
obj = {
1: { a: 'value' },
2: { },
3: { a: 'value' }
}
I have tried to .map through the keys with
arr.map(key => assocPath([key, 'a'], 'value', obj) )
, and also tried a way with arr.forEach(), but it doesn't work and i believe i may be missing some basic knowledge? Or is there an alternative ramda.js function i should use?
Take a look at my solution
const object = { 1: { }, 2: { }, 3: { } }
const array = ['1', '3']
function magic(obj, arr) {
return arr.reduce((acc, key) => ({
...acc,
[key]: { a: 'value' },
}), obj)
}
console.log(magic(object, array))
This is also can be achieved with ramda's functions
const object = { 1: { }, 2: { }, 3: { } }
const array = ['1', '3']
const magicR = R.reduce((acc, key) => R.assocPath([ key, 'a' ], 'value', acc))
console.log(magicR(object, array))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
You should be able to do this with .forEach():
arr.forEach(key => obj[key] = { a: 'value' });
The .map() function is for creating a new array from the elements of a source array, and you don't need to do that.
Ramda methods are immutable - they don't mutate the original object, but return a new one. The R.assocPath method is no different in this regard. To update the object, you'll need to iterate the array with R.reduce, use R.assocPath, get a new object, etc...
const { reduce, assocPath } = R
const fn = reduce((o, key) => assocPath([key, 'a'], 'value', o))
const obj = { 1: { }, 2: { }, 3: { } }
const arr = ['1', '2']
const result = fn(obj)(arr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Using underscore to determine if an object exists in a deeply nested array of objects?

This comparison is a bit odd as I have the following format:
Preferences Object:
{
models: [
{... attributes: {} },
{... attributes: {} },
{... attributes: {} }
]
}
Data Array:
[{}, {}, {}]
I have this object that contains an array of more objects with a key called attributes.
My Goal:
My goal is to see which items in the Data Array don't exist as the value to the attributes key in the models array using Underscore.JS.
Hacky Attempt:
This is definitely not how I want to code this, but localStorageLayers is the Data Array and the layerPrefs is the Preferences Object is the above labelling.
_.each(localStorageLayers, (localLayer) => {
var layerWasLoaded = false;
_.each(layerPrefs.models, (layerPref) => {
if (_.isEqual(layerPref.attributes, localLayer)) {
layerWasLoaded = true;
// Don't do anything
}
})
if (layerWasLoaded == false) {
// Do stuff
}
})
You could filter the localStorageLayers down to a subset where the localLayer is found to be equal to none (negated some) of the layerPrefs.models objects as compared to its attributes property.
I don't use lodash, but result should contain only the localStorageLayers that did not find equality in layerPrefs.models.
const layerPrefs = {
models: [
{attributes: {foo: "foo"} },
{attributes: {foo: "bar"} },
{attributes: {baz: "baz"} }
]
};
const localStorageLayers = [
{foo: "foo"}, {hot: "dog"}, {hot: "dog"}, {baz: "baz"}
];
const result = _.filter(localStorageLayers, localLayer =>
!_.some(layerPrefs.models, layerPref =>
_.isEqual(layerPref.attributes, localLayer)
)
);
console.log(result);
// Remove duplicates
const noDupes = _.uniqBy(result, _.isEqual);
console.log(noDupes);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
You could reverse the evaluation of each localLayer by doing _.every with !_.isEqual.
Use which ever seems clearer.
const result = _.filter(localStorageLayers, localLayer =>
_.every(layerPrefs.models, layerPref =>
!_.isEqual(layerPref.attributes, localLayer)
)
);

JS - Transform object to an object array with keys being part of array objects with util library

When writing lib/framework code API in js I often prefer this:
const definition = {
foo: {
someProp: 'foo-prop'
},
bar: {
someProp: 'bar-prop'
}
}
as an alternative to
const definition2 = [
{ name: 'foo', someProps:'foo-prop'},
{ name: 'bar', someProps:'bar-prop'}
]
as I find the former syntax friendly.
When processing the configuration I of course prefer array as shown in definition2 so I end up with this transformation code:
const arrayDefinition = Object.entries(objDefinition)
.map(([key, val]) => ({name: key, ...val}))
Is there a way how to reduce this boiler with a well known util library likelodash or ramba which would have function similar to this ?
const objToArray = obj => keyProp =>
Object.entries(obj)
.map(([key, val]) => ({[keyProp]: key, ...val}))
I prefer using existing libs to creating my own util functions.
If you want a easier way by using utility library like loadash or underscore then here is a easy solution for you
_.map(obj, function(val, key) {
return {
name: key,
someProp: val.someProp
}
})
This code will work for both, underscore.js as well as loadash, because the map function there is meant for both, object and array.
You could add a prototype to global Object
Object.prototype.toArr = function(propName){
return Object.keys(this).map(key => Object.assign({[propName]:key}, this[key]));
}
const definition = {
foo: {
someProp: 'foo-prop'
},
bar: {
someProp: 'bar-prop'
}
}
let arr = definition.toArr('name');
console.log(JSON.stringify(arr, null, ' '))

How to use lodash to find and return an object from Array?

My objects:
[
{
description: 'object1', id: 1
},
{
description: 'object2', id: 2
}
{
description: 'object3', id: 3
}
{
description: 'object4', id: 4
}
]
In my function below I'm passing in the description to find the matching ID:
function pluckSavedView(action, view) {
console.log('action: ', action);
console.log('pluckSavedView: ', view); // view = 'object1'
var savedViews = retrieveSavedViews();
console.log('savedViews: ', savedViews);
if (action === 'delete') {
var delete_id = _.result(_.find(savedViews, function(description) {
return description === view;
}), 'id');
console.log('delete_id: ', delete_id); // should be '1', but is undefined
}
}
I'm trying to use lodash's find method: https://lodash.com/docs#find
However my variable delete_id is coming out undefined.
Update for people checking this question out, Ramda is a nice library to do the same thing lodash does, but in a more functional programming way :)
http://ramdajs.com/0.21.0/docs/
lodash and ES5
var song = _.find(songs, {id:id});
lodash and ES6
let song = _.find(songs, {id});
docs at https://lodash.com/docs#find
The argument passed to the callback is one of the elements of the array. The elements of your array are objects of the form {description: ..., id: ...}.
var delete_id = _.result(_.find(savedViews, function(obj) {
return obj.description === view;
}), 'id');
Yet another alternative from the docs you linked to (lodash v3):
_.find(savedViews, 'description', view);
Lodash v4:
_.find(savedViews, ['description', view]);
You can do this easily in vanilla JS:
Using find:
const savedViews = [{"description":"object1","id":1},{"description":"object2","id":2},{"description":"object3","id":3},{"description":"object4","id":4}];
const view = 'object2';
const delete_id = savedViews.find(obj => {
return obj.description === view;
}).id;
console.log(delete_id);
Using filter (original answer):
const savedViews = [{"description":"object1","id":1},{"description":"object2","id":2},{"description":"object3","id":3},{"description":"object4","id":4}];
const view = 'object2';
const delete_id = savedViews.filter(function (el) {
return el.description === view;
})[0].id;
console.log(delete_id);
With the find method, your callback is going to be passed the value of each element, like:
{
description: 'object1', id: 1
}
Thus, you want code like:
_.find(savedViews, function(o) {
return o.description === view;
})
You don't need Lodash or Ramda or any other extra dependency.
Just use the ES6 find() function in a functional way:
savedViews.find(el => el.description === view)
Sometimes you need to use 3rd-party libraries to get all the goodies that come with them. However, generally speaking, try avoiding dependencies when you don't need them. Dependencies can:
bloat your bundled code size,
you will have to keep them up to date,
and they can introduce bugs or security risks
for this find the given Object in an Array, a basic usage example of _.find
const array =
[
{
description: 'object1', id: 1
},
{
description: 'object2', id: 2
},
{
description: 'object3', id: 3
},
{
description: 'object4', id: 4
}
];
this would work well
q = _.find(array, {id:'4'}); // delete id
console.log(q); // {description: 'object4', id: 4}
_.find will help with returning an element in an array, rather than it’s index. So if you have an array of objects and you want to find a single object in the array by a certain key value pare _.find is the right tools for the job.
Import lodash using
$ npm i --save lodash
var _ = require('lodash');
var objArrayList =
[
{ name: "user1"},
{ name: "user2"},
{ name: "user2"}
];
var Obj = _.find(objArrayList, { name: "user2" });
// Obj ==> { name: "user2"}
You can use the following
import { find } from 'lodash'
Then to return the entire object (not only its key or value) from the list with the following:
let match = find(savedViews, { 'ID': 'id to match'});
var delete_id = _(savedViews).where({ description : view }).get('0.id')
Fetch id basing on name
{
"roles": [
{
"id": 1,
"name": "admin",
},
{
"id": 3,
"name": "manager",
}
]
}
fetchIdBasingOnRole() {
const self = this;
if (this.employee.roles) {
var roleid = _.result(
_.find(this.getRoles, function(obj) {
return obj.name === self.employee.roles;
}),
"id"
);
}
return roleid;
},

Categories

Resources