Lodash - DifferenceBy with different identity - javascript

I have the following array:
[
{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
]
Every 5 seconds my application receives a new array and I need to compare the difference between the next one...
So the next array is:
[
{
conversation_id: 1
},
{
conversation_id: 2
},
{
conversation_id: 4
}
]
Considering that identity is different. How can I compare with the previous and get an array with the excluded item?
[
{
id: 3
}
]

Use _.differenceWith():
const prev = [{"id":1},{"id":2},{"id":3},{"id":4}]
const next = [{"conversation_id":1},{"conversation_id":2},{"conversation_id":4}]
const diff = _.differenceWith(prev, next, ({ id }, { conversation_id }) => _.eq(id, conversation_id))
console.log(diff)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>

I think you can use mix of javascript and lodash to solve this problem.
var arrayList = [
{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
var conv_array = [
{
conversation_id: 1
},
{
conversation_id: 2
},
{
conversation_id: 4
}
];
var itemsNotInArray = [];
arrayList.filter(function (item) {
if (!_.find(conv_array, {conversation_id: item.id })) {
console.log("not in array", item);
itemsNotInArray.push(item);
}
});
console.log("result you expected", itemsNotInArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Filter the first array and compare each value till you find a missing id :
var array1 = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
var array2 = [{
conversation_id: 1
},
{
conversation_id: 2
},
{
conversation_id: 4
}
];
var test = array1.filter(
conv => !array2.find(
id => id.conversation_id === conv.id
)
);
console.log(test)

From lodash documentation, the third argument to differenceBy is
[iteratee=_.identity] (Function): The iteratee invoked per element.
Based on this, you can use
var current = [
{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
and
var next = [
{
conversation_id: 1
},
{
conversation_id: 2
},
{
conversation_id: 4
}
];
then
var difference = _.differenceBy(current, next, function(obj) {
return obj.id || obj.conversation_id;
});
Or shortened with an arrow function:
var difference = _.differenceBy(current, next, (x) => x.id || x.conversation_id)

Related

Remove duplicate objects based on the same key from array and add their value to the object that is left

Consider the following array of objects in javascript
const array = [
{ 10205: 2 },
{ 10207: 3 },
{ 10205: 2 },
{ 10207: 1 }
]
I would like to have it converted to
array = [
{ 10205: 4 },
{ 10207: 4 }
]
const array = [{ 10205: 2 }, { 10207: 3 }, { 10205: 2 }, { 10207: 1 }];
const newArray = [];
array.forEach((element) => {
const elementKey = Object.keys(element)[0];
const foundIndex = newArray.findIndex((_) => Object.keys(_)[0] === elementKey);
if (foundIndex >= 0) {
newArray[foundIndex] =
{[elementKey]: newArray[foundIndex][elementKey] + element[elementKey]};
} else newArray.push(element);
});
console.log(newArray)
Please use reduce function.
const array = [
{ 10205: 2 },
{ 10207: 3 },
{ 10205: 2 },
{ 10207: 1 }
]
console.log(Object.values(array.reduce((acc, el)=>{
Object.keys(el).map((key)=>{
acc[key] = {
[key]: (acc?.[key]?.[key] ?? 0) + el[key],
}
})
return acc;
}, {})));

Group the parent object array based on the filter of the child object array

I've coded and I've got the results I want, but I think this code looks unclean.
const verses = [{
index: 1,
verses: [{
level: 1
},
{
level: 1
}
]
},
{
index: 2,
verses: [{
level: 1
},
{
level: 1
}
]
},
{
index: 3,
verses: [{
level: 2
}]
},
{
index: 4,
verses: [{
level: 2
}]
},
{
index: 5,
verses: [{
level: 2
},
{
level: 2
}
]
},
{
index: 6,
verses: [{
level: 3
},
{
level: 3
}
]
},
{
index: 7,
verses: [{
level: 3
},
{
level: 3
},
{
level: 4
},
{
level: 4
}
]
}
]
function getVerseIndexByLevel(level) {
const result = verses.map(v => {
const mappingByLevel = Math.max.apply(Math, [...new Set(v.verses.map(w => w.level))])
const mappingByVerse = v.index
return {
level: mappingByLevel,
verse: mappingByVerse
}
}).filter(v => v.level === level).map(v => v.verse)
return result
}
for (let i = 1; i <= 4; i++) {
console.log({
level: i,
verse: getVerseIndexByLevel(i)
})
}
Is my code above consuming too much performance?
Could you make it cleaner and simpler without changing the result at all?
-I don't know what details I have to add more, StackOverflow forced me to write this because the post is mostly code. but I hope you understand just by looking at the results of the code.-
On the performance end, the one thing I can see that could improve it would be to call getVerseIndexByLevel only once, and use the calculated result mapping, instead of calling it multiple times (requiring re-parsing the input every time). Something like
const verseIndicies = getVerseIndicies();
for (let i = 1; i <= 4; i++) {
console.log({
level: i,
verse: verseIndicies[i]
})
}
Another slight improvement - since you're using ES6 syntax, you don't need to .apply to Math.max - just spread the set into it.
You also don't need to turn the level numbers into a Set first - since it's being passed into Math.max anyway, repetitions aren't an issue.
const verses=[{index:1,verses:[{level:1},{level:1}]},{index:2,verses:[{level:1},{level:1}]},{index:3,verses:[{level:2}]},{index:4,verses:[{level:2}]},{index:5,verses:[{level:2},{level:2}]},{index:6,verses:[{level:3},{level:3}]},{index:7,verses:[{level:3},{level:3},{level:4},{level:4}]}];
function getVerseIndicies() {
const verseIndicies = {};
for (const v of verses) {
const level = Math.max(...v.verses.map(w => w.level));
verseIndicies[level] ??= [];
verseIndicies[level].push(v.index);
}
return verseIndicies;
}
const verseIndicies = getVerseIndicies();
for (let i = 1; i <= 4; i++) {
console.log({
level: i,
verse: verseIndicies[i]
})
}

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

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

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)

Nesting JavaScript every & some

I'm trying to figure out why this is returning false:
var goodUsers = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
];
var testUsers = [
{ id: 1 },
{ id: 2 },
{ id: 3 }
];
console.log(testUsers.every(testUser => {
goodUsers.some(goodUser => {
testUser.id === goodUser.id
})
}));
I think my problem is with how I am nesting some inside of every. Any help would be appreciated. Thanks!
Your callbacks for .some and .every didn't actually return anything. That's why you were getting false.
var goodUsers = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
];
var testUsers = [
{ id: 1 },
{ id: 2 },
{ id: 3 }
];
console.log(testUsers.every(testUser => {
return goodUsers.some(goodUser => {
return testUser.id === goodUser.id
});
}));
There is a difference between doing:
goodUser => testUser.id === goodUser.id
and
goodUser => { testUser.id === goodUser.id; }
The first - without {} - has an implicit return. It returns the value of the expression. It's the same as doing:
goodUser => { return testUser.id === goodUser.id; }
You were using {}, which starts a block of statements, and left out the return statement.
DOCS: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Categories

Resources