How can I group by the array using lodash or javascript - 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);

Related

Make an array A with the result of each value of array B splitted by pipe

I have an array of strings. Some of the strings within this array have a pipe character. I would like to split the strings by "|" and store all the unique values into a new array.
What would be an efficient way to get a temporary array with all the splited values in it, without using poor performance loops?
Once I have the temporary array with all the splited values in it, I plan de remove all duplicates like this :
var result = [...new Set(result)]
var arr = ["A|B|C","B|A","E|A|D","F"]
// result does not have to be sorted
var expectedResult = ["A","B","C","D","E","F"]
Use flatMap() and split() to get a single array, and use a Set to retain unique elements:
const array = ["A|B|C","B|A","E|A|D","F"];
const result = [...new Set(array.flatMap(v => v.split('|')))];
console.log(result);
.join('|') array as a string with pipes between all letters, then .split('|') by the pipe and then remove dupes with Set()
let data = ["A|B|C", "B|A", "E|A|D", "F"];
console.log([...new Set(data.join('|').split('|'))]);
I would go with
const result = arr.map(item => item.split("|")).flat();
const deduped = [...new Set(result)]
One more option:
const inputArray = ["A|B|C","B|A","E|A|D","F"];
const result = inputArray.reduce((acc, value) => acc.push(...value.split('|')) && acc, []);
console.log(result);
const splitSet = (arr) => {
const set = new Set();
for(const item of arr) {
const splited = item.split("|");
for(const piece of splited) {
set.add(piece);
}
}
return Array.from(set);
}
splitSet(arr); //result
The first thing that comes to my mind is this
const arr = ["A|B|C","B|A","E|A|D","F"];
const flatArr = arr.join('|').split('|');
const expectedResult = [...new Set(flatArr)];

How to get the matching second array of object in es6

I have two array of objects: - better solution
array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
Expected output be:
if first array and second array id matches means take the second array name
in above example id 2 matches and we need id:2,name: panasonics.
o/p:
[{id:1,name:"samsung"},{id:2,name:"panasonics"},{id:3,name:"Lg"},{id:5,name:"samsung"},{id:7,name:"Apple"}]
Combine the arrays using Array.concat(), reduce them into a Map by id, and then convert the Map's values to an array with Array.from():
const unionBy = (field, ...arrays) => Array.from(
[].concat(...arrays)
.reduce((r, o) => r.set(o.id, o), new Map)
.values()
);
const array1 = [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
const array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
const result = unionBy('id', array1, array2);
console.log(result);
You can use a simple .forEach() loop like below (you can also use a for loop if you want, but .forEach() is easier).
This code loops through array1, and loops through array2 in that loop. It then checks if the ids are the same. If there are, the name is appended to result.
const array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
const array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
let result = [];
array1.forEach(e1 => {
array2.forEach(e2 => {
if (e1.id == e2.id) {
result.push(e2.name);
}
});
});
console.log(result);
Use map() and concat() like the following code
array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
array2 = [{id:5,name:"samsung"}, {id:2,name:"panasonics"},{id:7,name:"Lg"}];
var array3=array1.map(function(i,v){
if(array2[v].id==i.id){
return array2[v]
}
else return i
})
array4=array3.concat(array2);
console.log(array4);

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

Transform from string array to hashmap in Lodash

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>

Lodash: Extract property, split array, get unique values

In my JS project, I am using Lodash library to Extract property, split array, get unique values.
var taskobj = [
{'taskno':'a', 'team':'1,2'},
{'taskno':'b', 'team':'3,4'},
{'taskno':'c', 'team':'2,4'},
];
//Looping through the object to convert string to array
_.forEach(taskobj, function(value, key) {
taskobj[key].team = _.split(taskobj[key].team,',');
});
// using _.map to extract team and return array
// using _.flatten to flatten array
// using _.uniq to get unique values from flattned array.
return _.uniq(_.flatten(_.map(taskobj,'team')));
// logs - [1,2,3,4]
Is this the most efficient way to achieve this?
you can use reduce and start with a new Set() and add the values of team every time ( then convert it back to an array with the spread operator )
var taskobj = [
{'taskno':'a', 'team':'1,2'},
{'taskno':'b', 'team':'3,4'},
{'taskno':'c', 'team':'2,4'},
];
var result = [...taskobj.reduce((acc, {team}) => {
team.split(',').forEach(e => acc.add(e))
return acc
}, new Set())]
console.log(result)
This can be achieved by using lodash#flatMap with an iteratee that splits the team string into an array, which is then flattened by the mentioned function and then use lodash#uniq to get the final result.
var result = _.uniq(_.flatMap(taskobj, ({ team }) => team.split(',')));
var taskobj = [
{'taskno':'a', 'team':'1,2'},
{'taskno':'b', 'team':'3,4'},
{'taskno':'c', 'team':'2,4'},
];
var result = _.uniq(_.flatMap(taskobj, ({ team }) => team.split(',')));
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Use simpler version
try this
var teams = [];
var taskobj = [
{'taskno':'a', 'team':'1,2'},
{'taskno':'b', 'team':'3,4'},
{'taskno':'c', 'team':'2,4'},
];
taskobj.map(obj => {
var teamSplit = obj.team.split(',');
teams = [...teams, ...teamSplit];
})
var uniqTeams = _.uniq(teams);
console.log('teams', teams);
console.log('uniqTeams', uniqTeams)
JsBin link
http://jsbin.com/bedawatira/edit?js,console

Categories