Transform from string array to hashmap in Lodash - javascript

What is the most precise way to transform from this
["access","edit","delete"]
to this
{access:true, edit:true, update:true}
Currently i loop to assign each value in object but i wonder if lodash already provide function for this

Use reduce(). This can all be done with a simple one-liner, that doesn't require any libraries:
const input = ["access","edit","delete"];
console.log(
input.reduce((obj, key) => { obj[key] = true; return obj; }, {})
);
With the new es6 spread syntax, you can even make this easier:
const input = ["access","edit","delete"];
console.log(
input.reduce((obj, key) => ({...obj, [key]: true}), {})
);

LODASH
You can map it to a array of entries and then simply use fromPairs of lodash
_.fromPairs(input.map(k=>[k, true]))
var input = ["access","edit","delete"];
var res = _.fromPairs(input.map(k=>[k,true]));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
ES6
You can map your input to a key (your each input) value (true) pair of objects and assign them.
Object.assign( ...input.map(k=>({[k]: true})))
var input = ["access","edit","delete"]
var res = Object.assign( ...input.map(k=>({[k]: true})));
console.log(res);
In case you want a Map object you can map your input to entries (as used in lodash example) and simply construct a new Map like
new Map(input.map(k=>[k, true]))

No need to import a library for something so simple, just reduce the array of keys into an object indexed by those keys:
const input = ["access","edit","delete"];
const output = input.reduce((a, key) => Object.assign(a, {[key]: true}), {});
console.log(output);
Or, assigning to the property of the accumulator rather than using Object.assign:
const input = ["access","edit","delete"];
const output = input.reduce((a, key) => {
a[key] = true;
return a;
}, {});
console.log(output);

If you absolutely want to use lodash (As opposed to the above vanilla javascript reduce() answers), you can use _.mapValues() to accomplish this:
const input = ["access","edit","delete"];
const output = _.mapValues(_.keyBy(input), () => true)
console.log(output);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js" integrity="sha256-7/yoZS3548fXSRXqc/xYzjsmuW3sFKzuvOCHd06Pmps=" crossorigin="anonymous"></script>

Related

how can i check if an array of objects contains a key which is in array of strings js?

We have an array of objects like
const arr = [{id: "someId", name: {...}}, ...];
const skippedKeys = ["id"...]
How can i filtered the array of object based on skipped keys?
The result should be:
const result = [{name: {...}}, ...];
Also i don't want to make a cycle inside the cycle.
the result also could be implemented using lodash library.
we should remove key with value as well.
Since you stated that it could be implemented using lodash, here is some code using lodash:
let result = _.map(arr, (el)=> _.omit(el, skippedKeys))
const result = arr.map(obj =>
Object.keys(obj).reduce(
(res, key) => (
skippedKeys.includes(key) ? res : {...res, [key]: obj[key]}
),
{},
));
It's simple and no need for any nested cycles. There are two option to do that
Using includes function
const result = arr.filter((item) => !result.includes(item.id));
Using set
const dataSet = new Set(skippedKeys);
const result = arr.filter((item) => !dataSet.has(item.id));
I prefer the second one as it excludes double checks. Hope the answer was helpful.

How can I group by the array using lodash or javascript

An Array is as follows:
let names = [
'Aditya',
'Aditya',
'Aditya',
'Abhi',
'Abhi',
'goyal'
]
I want to use lodash function and convert the names array which will return me as
[
Aditya(3),
Abhi(2),
goyal(1)
]
You can use _.countBy() to get an object of names with count, or a _.groupBy() if you want an object of names with arrays.
An array of arrays using _.groupBy() and _.values():
const names = ["Aditya","Aditya","Aditya","Abhi","Abhi","goyal"]
const result = _.values(_.groupBy(names))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
And object of counts with _.countBy:
const names = ["Aditya","Aditya","Aditya","Abhi","Abhi","goyal"]
const result = _.countBy(names)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Update - to get an array of strings that combine the key and value, you can use _.countBy(), and then _.map() it (lodash's _.map() works on objects as well).
const names = ["Aditya","Aditya","Aditya","Abhi","Abhi","goyal"]
const result = _.map(_.countBy(names), (v, k) => `${k}(${v})`)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
1) _.countBy the names to produce an object with name/count as the key/value.
2) Use _.entries to convert the object to a set of nest entry arrays.
3) _.map over the entries to produce the required output.
const names = ["Aditya","Aditya","Aditya","Abhi","Abhi","goyal"]
const toString = ([name, count]) => `${name}(${count})`;
const entries = _.entries(_.countBy(names));
const result = _.map(entries, toString);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Alternatively you can use vanilla JS to achieve the same thing in (almost) the same amount of code using reduce, Object.entries, and map.
const names = ["Aditya","Aditya","Aditya","Abhi","Abhi","goyal"]
const counts = names.reduce((acc, c) => {
return acc[c] = (acc[c] || 0) + 1, acc;
}, {});
const toString = ([name, count]) => `${name}(${count})`;
const entries = Object.entries(counts);
const result2 = entries.map(toString);
console.log(result2);

Lodash Group array of object and return array of key instead of object

I have an array of objects like this
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
Using _.groupBy(data,"age") will return name as a key with array of object.
How do I return only array of name?
Use Array#reduce
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const res = data.reduce((a,{name,age})=>{
if(!a[age]) a[age] = [];
a[age].push(name);
return a;
}, {});
console.log(res);
UPDATE
Thanks for help , i need a key to be age and a value to be array of
only names instead of object , i have edited my question
In this case you can use reduce
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"},{name:'abc', age:'23'}]
const op = data.reduce((out,{name,age})=>{
if(out[age]){
out[age].push(name)
} else {
out[age] = [name]
}
return out
},{})
console.log(op)
Simply you can use map
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const op = data.map(({name}) => name)
console.log(op)
As #ori asking for unique names you can use Set if you want unique one only
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"},{name:'abc', age:'23'}]
const op = [...new Set(data.map(({name}) => name))]
console.log(op)
Use _.flow() to create a function that groups by age, then map the groups with _.mapValues(), and use _.map() to pluck the names from the arrays:
const { flow, groupBy, mapValues, map } = _
const fn = flow(
arr => groupBy(arr, 'age'),
groups => mapValues(groups, g => map(g, 'name'))
)
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
And the terser lodash/fp version:
const { flow, groupBy, mapValues, map } = _
const fn = flow(
groupBy('age'),
mapValues(map('name'))
)
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
after grouping you need to iterate every group and return only name:
const res = _.chain(data)
.groupBy('age')
.mapValues(group => _.map(group, 'name'))
// or with FP .mapValues(_.partial(_.map, _, 'name'))
.value();

Converting a String to Multiple objects (javascript)

I have the following string: Jack:13,Phil:15,Lucy:12I'm trying to fetch objects from this string.
This string would have 3 people objects with their ages. How can this be achieved?
I've tried the following:
var s = 'Jack:13,Phil:15,Lucy:12'
var obj1 = eval("("+s+")");
var obj2 = JSON.parse(s);
Logging any of the obj variables returns errors. Am I missing a simple trick here? Any explanation would be appreciated, thanks.
In general, if you're doing replaces on a string to turn it into something you can pass eval or JSON.parse, that's probably not your best approach. An in particular, avoid using eval (or its cousin new Function) when you can (you certainly can here), and always avoid eval (or its cousin new Function) with untrusted input.
A pair of splits with map does it:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => e.split(":"))
.map(([name, age]) => ({name, age}));
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) { return e.split(":"); })
.map(function(e) { return {name: e[0], age: e[1]}; });
console.log(people);
I'm not sure why I did two maps rather than just doing the second split and creating the object in the same callback; I guess I'm thinking more and more in a "functional programming" way. I'd change it, but Eddie's answer already does it in a single map, so...
...(edit) but since it looks like you wanted separate properties rather than using the person's name like Eddie did, here's an example of the above but with just a single map:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => {
const [name, age] = e.split(":");
return {name, age};
});
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) {
var parts = e.split(":");
return {name: parts[0], age: parts[1]};
});
console.log(people);
You can split() the string and use map() to loop thru the array. This will return an array of objects.
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').map(o => {
let [k, v] = o.split(':');
return {[k]: v};
});
console.log(result);
If you want a single object, you can use reduce
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').reduce((c, o) => {
let [k, v] = o.split(':');
return Object.assign(c, {[k]: v});
}, {});
console.log(result);
You can try with:
const result = s.split(',')
.map(value => value.split(':'))
.reduce((acc, [name, value]) => {
acc[name] = +value;
return acc;
}, {});
Output:
{
"Jack": 13,
"Phil": 15,
"Lucy": 12
}
As I'm sure you've worked out there are many ways to do this, I thought I'd add another method
let s = 'Jack:13,Phil:15,Lucy:12'
let obj = {};
s.split(",").forEach(part => {
obj[part.split(":")[0]] = part.split(":")[1];
})
console.log(obj);
This is a simple split the string and then on each item of the new array do a split and push the results into an empty object already declared.
You could split the parts and build a new object with key/value pairs.
var string = 'Jack:13,Phil:15,Lucy:12',
result = Object.assign(...string
.split(',')
.map(s => (([k, v]) => ({ [k]: v }))(s.split(':')))
);
console.log(result);
For getting an array with objects
var string = 'Jack:13,Phil:15,Lucy:12',
result = string
.split(',')
.map(s => (([name, age]) => ({ name, age }))(s.split(':')));
console.log(result);
Easy to do with .map():
var s = 'Jack:13,Phil:15,Lucy:12';
var items = s.split(',')
.map((entry) => entry.split(':'))
.map((item) => ({name: item[0], age: item[1]}));
console.log(items);

Convert array of objects to plain object using Ramda

How can I convert an array of objects to a plain object?
Where each item of the array is an object with only one key:value pair and the key have an unknown name.
I have this
const arrayOfObject = [
{KEY_A: 'asfas'},
{KEY_B: 'asas' }
]
let result = {}
const each = R.forEach((item) => {
const key = R.keys(item)[0]
result[key] = item[key]
})
return result
But I dislike that solution because the forEach is using a global variable result and I'm not sure how to avoid side effects here.
Ramda has a function built-in for this, mergeAll.
const arrayOfObject = [
{KEY_A: 'asfas'}
,{KEY_B: 'asas' }
];
R.mergeAll(arrayOfObject);
//=> {"KEY_A": "asfas", "KEY_B": "asas"}
Since everybody is using ES6 already (const), there is a nice pure ES6 solution:
const arrayOfObject = [
{KEY_A: 'asfas'},
{KEY_B: 'asas'}
];
Object.assign({}, ...arrayOfObject);
//=> {KEY_A: "asfas", KEY_B: "asas"}
Object.assing merges provided objects to the first one, ... is used to expand an array to the list of parameters.
Use reduce instead:
const arrayOfObject = [
{KEY_A: 'asfas'}
,{KEY_B: 'asas' }
];
const each = R.reduce((acc,value) => {
const key = R.keys(value)[0];
acc[key] = value[key];
return acc;
},{},arrayOfObject);
Since your array is an array of objects, you could also just call merge inside a reduce:
const each2 = R.reduce((acc,value) => R.merge(value,acc),{},arrayOfObject);
Here is a jsbin with both examples:
http://jsbin.com/mifohakeru/edit?js,console,output

Categories