lodash javascript array of duplicates that match multiple parameters - javascript

I have an array, to simplify lets say persons with first, last, and age. I want to make a new array of all persons that have the same first name, same last name and same age. For example my starting array:
[
{id: 1, first: 'fred', last: 'smith', age: 21},
{id: 2, first: 'fred', last: 'smith', age: 21},
{id: 3, first: 'tom', last: 'smith', age: 21},
{id: 4, first: 'fred', last: 'smith', age: 32}
]
I would like to return the duplicates that match first/last/age:
[
{id: 1, first: 'fred', last: 'smith', age: 21},
{id: 2, first: 'fred', last: 'smith', age: 21}
]
I'm struggling with _.uniq to figure out how to do this, any help is appreciated.

You can make use of _.groupBy() to group values, make sure that it is grouped by values that you determine to be the criteria for a duplicate. You can then _.filter() each grouped values by the lengths of the arrays they accumulated and then _.flatten() it to obtain the final array.
var data = [
{id: 1, first: 'fred', last: 'smith', age: 21},
{id: 2, first: 'fred', last: 'smith', age: 21},
{id: 3, first: 'tom', last: 'smith', age: 21},
{id: 4, first: 'fred', last: 'smith', age: 32}
];
var result = _(data)
.groupBy(i => _(i).pick('first', 'last', 'age').values().value())
.filter(i => i.length > 1)
.flatten()
.value();
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js"></script>

Related

Remove duplicate objects from an array with Keys

How to filter array of objects by property? for example in this array if two or more objects have same properties like name and lastname I want to remove either of them and leave only unique one in an array. example arr:
[ {name: "George", lastname: "GeorgeLast", age: 12},
{name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
result should be either
[ {name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
or
[ {name: "George", lastname: "GeorgeLast", age: 12},
{name: "Bob", lastname: "GeorgeLast", age: 12}]
Apply the technique shown in this answer, which is:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
...but using findIndex with some criteria rather than just indexOf.
let people = [
{ name: "George", lastname: "GeorgeLast", age: 12 },
{ name: "George", lastname: "GeorgeLast", age: 13 },
{ name: "Bob", lastname: "GeorgeLast", age: 12 }
]
let result = people.filter(
(person, index) => index === people.findIndex(
other => person.name === other.name
&& person.lastname === other.lastname
));
console.log(result);
As for whether it keeps 12-year-old George or 13-year-old George, it is a matter of how findIndex works, which so happens to return the first matching element. So in your example case it will keep 12-year-old George.
The Map object holds key-value pairs and remembers the original insertion order of the keys.
const arr = [
{ name: "George", lastname: "GeorgeLast", age: 12 },
{ name: "George", lastname: "GeorgeLast", age: 13 },
{ name: "Bob", lastname: "GeorgeLast", age: 12 }
];
const newMap = new Map();
arr.forEach((item) => newMap.set(item.name, item));
console.log([...newMap.values()]);
Another solution.
Here you don't need to iterate through the list n*n/2 times (if I count correctly).
On the other hand, this one looks less concise and uses more memory.
Use whichever you prefer.
const arr = [
{name: "George", lastname: "GeorgeLast", age: 12},
{name: "George", lastname: "GeorgeLast", age: 13},
{name: "Bob", lastname: "GeorgeLast", age: 12}
];
const obj = {}
arr.forEach(v => {
if (!obj[v.name]) {
obj[v.name] = {}
}
if (!obj[v.name][v.lastname]) {
obj[v.name][v.lastname] = v;
}
})
const result = [];
Object.values(obj).forEach(nameObj =>
Object.values(nameObj).forEach(surnObj => result.push(surnObj))
);
console.log(result)

array of object into array of object but different (javascript)

Using javascript, I have this array:
people = [{name: carlo, lastname: Garcia, age: 28},
{name: maria, lastname: pia, age: 20},
{name: elly, lastname: martinez, age: 25}]
I would like to transform it into:
arrayList = [{data: {name: carlo, lastname: garcia, age: 28}, checked: false},
{data: {name: carlo, lastname: garcia, age: 28}, checked: false},
{data: {name: carlo, lastname: garcia, age: 28}, checked: false}]
How can I do it?
You want to use Array.prototype.map
var people = [{ name: "carlo", lastname: "Garcia", age: 28 }, { name: "maria", lastname: "pia", age: 20 }, { name: "elly", lastname: "martinez", age: 25 }]
var arrayList = people.map(person => ({
data: person,
checked: false,
}))
console.log(arrayList);
Just use map(). Return an object with data and checked fields.
Where:
data is set to each person
checked is set to false
people = [{name: 'carlo', lastname: 'Garcia', age: 28},{name: 'maria', lastname: 'pia', age: 20},{name: 'elly', lastname: 'martinez', age: 25}]
arrayList = people.map(p => ({ data: p, checked: false }))
console.log(arrayList)

Grouping nested dada

Say you have csv data file like this:
name, age
Bob, 27
George, 25
Bill, 22
Henry,27
Carol,25
Mary, 28
Harold,27
Jane, 25
I want to aggregate totals by age for a bar chart. So that I get totals like this: age 27(3), age 25(2), etc.
I am using d3 v4
As mentioned in the comments, you could use d3.nest:
const data = [
{name: 'Bob', age: 27},
{name: 'George', age: 25},
{name: 'Bill', age: 2},
{name: 'Henry', age: 27},
{name: 'Carol', age: 25},
{name: 'Mary', age: 28},
{name: 'Harold', age: 27},
{name: 'Jane', age: 25},
];
console.log(d3.nest()
.key(d => d.age)
.rollup(results => results.length)
.entries(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

reduce an array of objects in javascript

how can I reduce an array of objects of this type:
[
{id: 1, name: 'jhon', lastname: 'doe', age: 30},
{id: 2, name: 'max', lastname: 'wall', age: 20},
{id: 3, name: 'fer', lastname: 'baneg', age: 15}
]
I need to get a new array just with these values:
[
{id: 1, name: 'jhon'},
{id: 2, name: 'max'},
{id: 3, name: 'fer'}
]
You can use map() method for this with ES6 parameter destructuring.
const data = [{id: 1, name: 'jhon', lastname: 'doe', age: 30},{id: 2, name: 'max', lastname: 'wall', age: 20},{id: 3, name: 'fer', lastname: 'baneg', age: 15}]
const result = data.map(({id, name}) => ({id, name}))
console.log(result)

Cannot Read Property of Undefined using Reduce

I have an object with sales numbers and want to get return the name and sales of the highest seller, but I keep getting an error of cannot read property of undefined:
var salesTeam = [{name: {first: 'aleen', last: 'atkins'}, age: 26, sales: '$2314'},
{name: {first: 'alvaro', last: 'angelos'}, age: 55, sales: '$1668'},
{name: {first: 'denese', last: 'dossett'}, age: 29, sales: '$9248'},
{name: {first: 'douglas', last: 'denney'}, age: 53, sales: '$5058'},
{name: {first: 'earline', last: 'erickson'}, age: 19, sales: '$18876'},
{name: {first: 'herman', last: 'hazell'}, age: 25, sales: '$2746'},
{name: {first: 'homer', last: 'hirth'}, age: 26, sales: '$474'},
{name: {first: 'hwa', last: 'heidt'}, age: 53, sales: '$9607'},
{name: {first: 'hyon', last: 'hampshire'}, age: 46, sales: '$13598'},
{name: {first: 'issac', last: 'ingerson'}, age: 45, sales: '$5225'},
{name: {first: 'jeraldine', last: 'joplin'}, age: 39, sales: '$2891'},
{name: {first: 'jin', last: 'jeffrey'}, age: 17, sales: '$14402'},
{name: {first: 'joleen', last: 'jolin'}, age: 45, sales: '$15736'},
{name: {first: 'jude', last: 'jarrett'}, age: 53, sales: '$7557'},
{name: {first: 'magda', last: 'mireles'}, age: 18, sales: '$1498'},
{name: {first: 'mistie', last: 'montealegre'}, age: 31, sales: '$6920'},
{name: {first: 'nancy', last: 'napoli'}, age: 49, sales: '$5255'},
{name: {first: 'regine', last: 'rohrbaugh'}, age: 33, sales: '$7881'},
{name: {first: 'rolando', last: 'riebel'}, age: 35, sales: '$8573'},
{name: {first: 'scarlett', last: 'stagg'}, age: 36, sales: '$7126'},
{name: {first: 'sherron', last: 'strawn'}, age: 36, sales: '$8848'},
{name: {first: 'susan', last: 'shilling'}, age: 29, sales: '$8542'},
{name: {first: 'tama', last: 'tworek'}, age: 16, sales: '$9200'},
{name: {first: 'tonisha', last: 'taunton'}, age: 41, sales: '$5219'},
{name: {first: 'vergie', last: 'villescas'}, age: 25, sales: '$8712'}];
var highestEarner = function (companies) {
var ret = companies.reduce(function(acc,element,i){
if (parseInt(element['sales'].slice(1)) > acc['sales']){
acc['sales'] = element['sales'];
acc['name'] = element['name']['first'] +" "+ element['name']['last'];
}
},{sales: 0, name: ''});
return ret;
};
console.log(highestEarner(salesTeam));
You need to return the accumulator in each iteration, ie you are missing return acc after the if {...}. Also, you're assigning the currency-formatted value to acc['sales'] so you'll need to slice and parseInt that too (or just store the numeric value)...
const salesTeam = [{"name":{"first":"aleen","last":"atkins"},"age":26,"sales":"$2314"},{"name":{"first":"alvaro","last":"angelos"},"age":55,"sales":"$1668"},{"name":{"first":"denese","last":"dossett"},"age":29,"sales":"$9248"},{"name":{"first":"douglas","last":"denney"},"age":53,"sales":"$5058"},{"name":{"first":"earline","last":"erickson"},"age":19,"sales":"$18876"},{"name":{"first":"herman","last":"hazell"},"age":25,"sales":"$2746"},{"name":{"first":"homer","last":"hirth"},"age":26,"sales":"$474"},{"name":{"first":"hwa","last":"heidt"},"age":53,"sales":"$9607"},{"name":{"first":"hyon","last":"hampshire"},"age":46,"sales":"$13598"},{"name":{"first":"issac","last":"ingerson"},"age":45,"sales":"$5225"},{"name":{"first":"jeraldine","last":"joplin"},"age":39,"sales":"$2891"},{"name":{"first":"jin","last":"jeffrey"},"age":17,"sales":"$14402"},{"name":{"first":"joleen","last":"jolin"},"age":45,"sales":"$15736"},{"name":{"first":"jude","last":"jarrett"},"age":53,"sales":"$7557"},{"name":{"first":"magda","last":"mireles"},"age":18,"sales":"$1498"},{"name":{"first":"mistie","last":"montealegre"},"age":31,"sales":"$6920"},{"name":{"first":"nancy","last":"napoli"},"age":49,"sales":"$5255"},{"name":{"first":"regine","last":"rohrbaugh"},"age":33,"sales":"$7881"},{"name":{"first":"rolando","last":"riebel"},"age":35,"sales":"$8573"},{"name":{"first":"scarlett","last":"stagg"},"age":36,"sales":"$7126"},{"name":{"first":"sherron","last":"strawn"},"age":36,"sales":"$8848"},{"name":{"first":"susan","last":"shilling"},"age":29,"sales":"$8542"},{"name":{"first":"tama","last":"tworek"},"age":16,"sales":"$9200"},{"name":{"first":"tonisha","last":"taunton"},"age":41,"sales":"$5219"},{"name":{"first":"vergie","last":"villescas"},"age":25,"sales":"$8712"}];
var highestEarner = function (companies) {
var ret = companies.reduce(function(acc,element) {
let currentSales = parseInt(element.sales.slice(1))
if (currentSales > acc.sales) {
acc.sales = currentSales;
acc.name = `${element.name.first} ${element.name.last}`
}
return acc;
},{sales: 0, name: ''});
return ret;
};
console.log(highestEarner(salesTeam));
The simple rule while working with reducer is that, whatever data format you have in each element of the array, make sure you are returning the same format including all the elements in every run so that it can use the returned value as accumulator (acc) for the next run.
A simple mistake which I learned from below:
This fixed the issue.

Categories

Resources