Group array of objects by value and get count of the groups - javascript

I have an array objects
[ { group: 1 }, { group: 2 ], { group: 2 } ]
I want to get the count of distinct groups by property value 'group', expecting the result of 2
How to do this by es6 or reduce?

You just need to store counts in your aggregator for each key using reduce.
const data = [ { 'group': 1 }, { 'group': 2 }, { 'group': 2 } ]
const groups = data.reduce((agg, curr)=>{
if(agg[curr.group]){
agg[curr.group] += 1
}
else{
agg[curr.group] = 1
}
return agg
},{})
console.log(groups)

i'm not sure that i understand your question right.
If you want group your object by value equals to 2, using filter will be useful
const obj = [ { group: 1 }, { group: 2 }, { group: 2 }, { group: 2 } ]
// new array with group value equals to 2
const countGroup = () => {
return obj.filter(it => it.group === 2)
}
// count how many group with value equals to 2
const countGroupCount = () => {
return obj.filter(it => it.group === 2)
}
console.log(countGroup())
console.log(countGroupCount())

Related

Loop through two arrays and check if key value in items of the first array are present in the second [JavaScript] [duplicate]

This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed last month.
This post was edited and submitted for review last month and failed to reopen the post:
Original close reason(s) were not resolved
I am trying to loop a array of objects and compare it with another array and check of the key value is present in the array which is to be compared. Here I am not going to check for the array length too.
Example
Array1 is the array which needs to be compared to array 2
[{name:'Linus',id:1},{name:'Anthony',id:2},{name:'Carl',id:3}]
Array 2
[{name:'Linus',id:1},{name:'Anthony',id:2},{name:'Beth',id:3},{name:'Kyle',id:4}]
I am trying to validate if all the id values in array 1 are present in array 2 and if not present then I expect a boolean value and get the best solution in terms of performance.
array1.every(item1 => array2.some(item2 => item1.id === item2.id))
Pretty easy using the .findIndex() in a loop and filter depending upon your needs.
const array1 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Carl',
id: 3
}];
const array2 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Beth',
id: 3
}, {
name: 'Kyle',
id: 4
}];
array1.forEach((a1) => {
const idx = array2.findIndex((x) => {
return x.id === a1.id
});
console.log(idx);
});
// idx set to -1 if it is not found
array2.forEach((a2) => {
const idx = array1.findIndex((x) => {
return x.id === a2.id
});
console.log(idx);
});
let matches = array2.filter((a) => {
return array1.findIndex((x) => {
return x.id === a.id
}) > -1;
});
console.log(matches);
let nomatches = array2.filter((a) => {
return array1.findIndex((x) => {
return x.id === a.id
}) == -1;
});
console.log(nomatches);
const arr1 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Carl',
id: 3
}];
const arr2 = [{
name: 'Linus',
id: 1
}, {
name: 'Anthony',
id: 2
}, {
name: 'Beth',
id: 3
}, {
name: 'Kyle',
id: 4
}]
let compareTwoArrayOfObjects = (
first_array_of_objects,
second_array_of_objects
) => {
return (
first_array_of_objects.length === second_array_of_objects.length &&
first_array_of_objects.every((element_1) =>
second_array_of_objects.some(
(element_2) =>
element_1.id === element_2.id
)
)
);
};
console.log(compareTwoArrayOfObjects(arr1, arr2));
You can do it with this method to compare each object's element and check their id value

How to add a value to an array in a specific location with JS

I have an array of objects:
const array = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 }
];
and I need to add another entry to it, but it needs to be placeable within any location in the array. So for example:
array.push({ id: 5, after_id: 2 }); and this should place the new entry between ids 2 and 3. Is there some standard way of doing this?
#p.s.w.g Has posted what is probably the best solution in a comment already, but I thought I'd post my original solution here as an answer now this is reopened.
You can use some to iterate through the array until the correct index is found, then you can slice the array and insert the item at the relevant index:
const arrayTest = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
const insertAfterId = (array, item, idAfter) => {
let index = 0;
array.some((item, i) => {
index = i + 1;
return item.id === idAfter
})
return [
...array.slice(0, index),
item,
...array.slice(index, array.length),
];
};
const result = insertAfterId(arrayTest, {
id: 6
}, 2)
console.dir(result)

Compare 2 arrays and assign matching value [duplicate]

This question already has answers here:
Merge property from an array of objects into another based on property value lodash
(5 answers)
Closed 4 years ago.
I have 2 array of objects
The first one called data:
const data = [
{
id: 1,
nombre: 'Piero',
},
{
id: 4,
nombre: 'Nelson',
},
{
id: 7,
nombre: 'Diego'
},
]
and the second called subs:
const subs = [
{
id: 1,
name: 'Temprano',
},
{
id: 4,
name: 'A tiempo',
},
{
id: 7,
name: 'Tarde'
},
]
In which I want to compare that if they have the same ID, the subs array will pass its name value to it and if it does not match that it puts a '-' in the data array, try this way:
data.forEach((d)=>{
subs.forEach((s)=>{
if(d.id === s.id){
d.subname = s.name;
}
else {
d.subname = '-';
}
});
});
But always assign the values with '-' as if it does not match any. What part am I doing wrong? Is there any other simpler way to do this? I would greatly appreciate your help.
The size of the subs array may vary.
It looks like you are not exiting the inner loop when a successful match is found.
In the first example where you are looking for a match for Piero, in your first iteration 1===1 and d.subname is correctly set to 'Temprano'. However, you then continue to compare the values- 1 !== 4 so Temprano is overwritten with '-', and 1 !== 7 so it is overwritten again.
An alternate approach:
data.forEach(d => {
const match = subs.find(s => s.id === d.id);
d.subname = match ? match.name : '-';});
I'd also recommend adding a case where you're not expecting to find a match, so you can see that it works in both cases!
https://codepen.io/anon/pen/MGGBLP?editors=0010
const data = [
{
id: 1,
nombre: 'Piero',
},
{
id: 4,
nombre: 'Nelson',
},
{
id: 7,
nombre: 'Diego'
},
];
const subs = [
{
id: 1,
name: 'Temprano',
},
{
id: 4,
name: 'A tiempo',
},
{
id: 7,
name: 'Tarde'
},
];
// by caching one of the arrays in an object, it reduces the run time to linear.
const obj = subs.reduce((acc, item) => {
acc[item.id] = item;
return acc;
})
data.forEach(d => {
if (d.id in obj) {
d.subname = obj[d.id].name;
} else {
d.subname = '-';
}
});
console.log(data);
You just need two lines for this:
var findIds = id => subs.find(findId => findId.id === id);
data.forEach(findId => Object.assign(findId, findIds(findId.id)));
Your data array object should now include the name property from it's respective id sharing object in subs array.
jsFiddle: https://jsfiddle.net/AndrewL64/9k1d3oj2/1/

Remove last added value from array without mutating it

dontMutateMeArray=[1,2,3,3,3,4,5];
toBeRemoved=3;
newArray=dontMutateMeArray.something(toBeRemoved); // [1,2,3,3,4,5]
iDontWantArray=dontMutateMeArray.filter(value=>value===toBeRemoved); // [1,2,4,5]
I indeed need it for array of objects too. And I specifically need to remove the last added object (ie. the one with higher index in the array). Something like:
dontMutateMeArray=[{id:1},{id:2},{id:3,sth:1},{id:3,sth:42},{id:3,sth:5},{id:4},{id:5}];
toBeRemoved=3;
newArray=dontMutateMeArray.something(toBeRemoved); // [{id:1},{id:2},{id:3,sth:1},{id:3,sth:42},{id:4},{id:5}]
iDontWantArray=dontMutateMeArray.filter(obj=>obj.id===toBeRemoved); // [{id:1},{id:2},{id:4},{id:5}]
iDontWantArray2=dontMutateMeArray.blahBlah(toBeRemoved); // [{id:1},{id:2},{id:3,sth:1},{id:3,sth:5},{id:4},{id:5}]
You could iterate from right and check with a closure.
var dontMutateMeArray = [{ id: 1 }, { id: 2 }, { id: 3, sth: 1 }, { id: 3, sth: 42 }, { id: 3, sth: 5 }, { id: 4 }, { id: 5 }],
toBeRemoved = 3,
newArray = dontMutateMeArray.reduceRight((found => (r, a) => (!found && a.id === toBeRemoved ? found = true : r.unshift(a), r))(false), []);
console.log(newArray);

How to combine _.map and _.filter in a more efficient way?

I am using Lodash in my Angular project and I was wondering if there is a better way to write the following code:
$scope.new_arr = _.map(arr1, function(item){
return _.assign(item, {new_id: _.find(arr2, {id: item.id})});
});
$scope.new_arr = _.filter($scope.new_arr, function (item) {
return item.new_id !== undefined;
});
I am trying to combine values from one array to same objects in other array, and I want to ignore the objects that not appear in both arrays (it is something like join or left outer join in the sql language).
Here is a fiddle with an example of this code: Click me!
i think is better to use chaining
$scope.new_arr = _.chain(arr1)
.map(function(item) {
return _.merge(
{}, // to avoid mutations
item,
{new_id: _.find(arr2, {id: item.id})}
);
})
.filter('new_id')
.value();
https://jsfiddle.net/3xjdqsjs/6/
try this:
$scope.getItemById = (array, id) => {
return array.find(item => item.id == id);
};
$scope.mergeArrays = () => {
let items_with_ids = arr1.filter(item => !_.isNil($scope.getItemById(arr2,item.id)));
return items_with_ids.map(item => _.assign(item, {new_id: $scope.getItemById(arr2,item.id)}));
};
The answers provided here are all runtime of O(n^2), because they first run an outer loop on the first array, with an inner loop on the second array. You can instead run this in O(n). First, create a hashmap of all the ids in arr2 in a single loop; this will allow us an order 1 lookup. In the second loop on arr1, check this hashmap to determine if those items exist with O(n). Total Complexity is n + n = 2n, which is just O(n).
// provision some test arrays
var arr1 = [
{
id: 2
},
{
id: 4
},
{
id: 6
}
]
var arr2 = [
{
id: 3
},
{
id: 4
},
{
id: 5
},
{
id: 6
}
]
// First, we create a map of the ids of arr2 with the items. Complexity: O(n)
var mapIdsToArr2Items = _.reduce(arr2, function(accumulator, item) {
accumulator[item.id] = item;
return accumulator;
}, {});
// Next, we use reduce (instead of a _.map followed by a _.filter for slightly more performance.
// This is because with reduce, we loop once, whereas with map and filter,
// we loop twice). Complexity: O(n)
var combinedArr = _.reduce(arr1, function(accumulator, item) {
// Complexity: O(1)
if (mapIdsToArr2Items[item.id]) {
// There's a match/intersection! Arr1's item matches an item in arr 2. Include it
accumulator.push(item);
}
return accumulator;
}, []);
console.log(combinedArr)
You could first make a Map with arr1 and then map the items of arr2 with the properties of arr1.
var arr1 = [{ id: 1, title: 'z' }, { id: 2, title: 'y' }, { id: 3, title: 'x' }, { id: 4, title: 'w' }, { id: 5, title: 'v' }],
arr2 = [{ id: 2, name: 'b' }, { id: 3, name: 'c' }, { id: 4, name: 'd' }, { id: 5, name: 'e' }],
map = new Map(arr1.map(a => [a.id, a])),
result = arr2.map(a => Object.assign({}, a, map.get(a.id)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources