Typescript difference of two object arrays - javascript

I have two object arrays and want to find the items that are missing in the second array but are part of the first array,basically array1-array2.I tried to use filter but I'm unable to get the desired result.Please help.Thanks in advance.
Here is the code:
testData=[
{id: 0, name: "policy001"},
{id: 2, name: "policy002"}];
sourceData= [
{id: 0, name: "policy001"},
{id: 2, name: "policy002"},
{id: 3, name: "policy003"},
{id: 4, name: "policy004"},
{id: 5, name: "policy005"},
];
let missing = sourceData.filter(item => testData.indexOf(item) < 0);
console.log("Miss")
console.log(missing )//Returns the sourceData instead of diff.

Try findIndex():
The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test.
testData = [{
id: 0,
name: "policy001"
},
{
id: 2,
name: "policy002"
}
];
sourceData = [{
id: 0,
name: "policy001"
},
{
id: 2,
name: "policy002"
},
{
id: 3,
name: "policy003"
},
{
id: 4,
name: "policy004"
},
{
id: 5,
name: "policy005"
},
];
console.log(sourceData.filter(item => testData.findIndex(x => x.id == item.id) < 0))

The reason your code did not work is that object inside array are "addresses" to the objects. So of course the indexOf did not work
try below:
let missing = sourceData.filter(a => !testData.find(b => a.id === b.id));

You're getting this undesired behavior because what you're doing in your filter is comparing the items' references rather than their values. if you want to compare that those objects are actually identical in values (because they have different references), you need to do the following:
let missing = sourceData.filter(sourceItem =>
testData.every(testItem =>
testItem.id !== sourceItem.id && testItem.name !== sourceItem.name
)
)
this means - filter out those element of sourceData, for which none of the elements in testData has the same id or name. They are "missing".

Related

How to delete objects from array by list of IDs in TypeScript

I have an array of objects that have specific IDs and another second array of objects that also have specified IDs. I want to delete objects from the first array that have the same ID as objects in the second array. How can I do it?
Is that what you're trying to do?
let arr1 = [{
id: 0,
name: 'x'
}, {
id: 1,
name: 'y'
}, {
id: 2,
name: 'z'
}];
const arr2 = [{
id: 0,
name: 'x'
}];
arr1 = arr1.filter(element => !arr2.find(el => el.id === element.id));
console.log(arr1);
Here is a link that seems to fit what you are trying to accomplish.
How to merge two arrays in JavaScript and de-duplicate items
You can simply achieve this requirement with the help of Array.filter() along with the Array.includes() method.
Live Demo :
const arr1 = [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}, {
id: 5
}];
const arr2 = [{
id: 2
}, {
id: 3
}, {
id: 5
}];
const res = arr1.filter(obj => !arr2.map(({ id }) => id).includes(obj.id));
console.log(res);

Compare Javascript Object field with another Object field [duplicate]

This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed last year.
I have two Objects one of them has the Store Name and the other object has the Price for an item along with the Store ID on both objects. Such as;
obj1 = [
{id: 1,name: "Store1"},
{id: 2,name: "Store2"},
{id: 3,name: "Store3"}
];
obj2= [
{ id: 1, price: 100 },
{ id: 2, price: 200 },
{ id: 3, price: 300 }
];
What I want to achieve is that compare obj1 id with obj2 id if they are the same get the price and the store name from the same id. What is the best way to achieve this? I have been trying to use Array.map or filter but can't really make it work. Thank you!
You can use map & find
const obj1 = [{
id: 1,
name: "Store1"
},
{
id: 2,
name: "Store2"
},
{
id: 3,
name: "Store3"
},
{
id: 4,
name: "Store3"
}
];
const obj2 = [{
id: 1,
price: 100
},
{
id: 2,
price: 200
},
{
id: 3,
price: 300
}
];
const newData = obj1.map((item, index) => {
return {
...item,
// if the item exist in obj2 then get the price else assign empty string
price: obj2.find(elem => elem.id === item.id) ? .price || ''
}
});
console.log(newData)

Delete multiple objects in an array by id

I have a main array of objects with each object having some key/values as well as a "id" key with 1,2,3,4,5, etc
Now I have another array representing just id's (like [2,3])
I want to use this array to delete objects from the main array...so in this case, objects from the main array having id's 2 & 3 should be deleted
While I am aware of findBy(id), I am not sure if that can be used to delete multiple objects at once.
You can use filter. In the filter callback function check if the id is also there in id array by using includes
let idArr = [1, 2]
let obj = [{
id: 1,
name: 'abc'
},
{
id: 2,
name: 'abc'
},
{
id: 3,
name: 'abc'
},
{
id: 4,
name: 'abc'
}
];
let data = obj.filter(item => !idArr.includes(item.id));
console.log(data);
console.log(obj)
using filter might work well here. you could write something like:
var newArray = oldArray.filter(object => !ids.includes(object.id))
You can do it, like this:
[2,3].forEach(key => {
delete object[key];
})
You can use filter method for this.
Ex:
let id = 2;
let list = [{
Id: 1,
Name: 'a'
}, {
Id: 2,
Name: 'b'
}, {
Id: 3,
Name: 'c'
}];
let lists = list.filter(x => {
return x.Id != id;
})
console.log(lists);
Assuming you want to delete items from the original array by entirely removing the element from the array (and you don't want to get a new array), you can take advantage of
Array.splice
let idArr = [1, 2];
let obj = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
for (let id of idArr) {
// look for the element by its id.
const objIdRef = obj.find(i => i.id === id);
// if it actually exists, splice it.
objIdRef && obj.splice(obj.indexOf(objIdRef), 1);
}
console.log(obj);
If the obj array is big, you might want to make a map from it before processing the id array, so that the complexing is reduced to O(1) when the delete process begins.
Perhaps This is what you want:
var arr= [{id:1, name: "foo"}, {id:2, name: "bar"}, {id:3, name:"not to be deleted"}];
var idsToDelete = [1, 2];
var res = arr.map((i, idx)=>{
return arr[idx] = idsToDelete.includes(i.id)? undefined : arr[idx]
}).filter(i=>i)
console.log(res)
You can try Lodash.js functions _.forEach() and _.remove()
let valuesArr = [
{id: 1, name: "dog"},
{id: 2, name: "cat"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
{id: 5, name: "pig"},
];
let removeValFromIndex = [
{id: 2, name: "cat"},
{id: 5, name: "pig"},
];
_.forEach(removeValFromIndex, (indi) => {
_.remove(valuesArr, (item) => {
return item.id === indi.id;
});
})
console.log(valuesArr)
/*[
{id: 1, name: "dog"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
]; */
Don't forget to clone (_.clone(valuesArr) or [...valuesArr]) before mutate your array

add an object to an array if it doesn't have the same key with one of the objects in the array

I'm using Lodash. I have the array below:
const array = [{id:1,name:a},{id:2,name:b},{id:3,name:c},{id:4,name:d},{id:5,name:e}];
and I'm about to add another object to this array but before that, I need to check if the new object's name is already in the array or not and if there is one with the name I won't add the new object anymore.
I know some ways to do it, for instance, a loop with _.map, but want to make sure if there is an easier way.
You could use Lodash's some which if provided with an appropriate predicate e.g. (item => item.name === newName) will return a boolean indicating whether or not the item already exists (in this case, true would mean the name already exists). The benefit of using this over other iterating methods is that it will stop as soon as it finds one that returns true resulting in better performance.
With native javascript , you can use findIndex, this will return the index of the object where the name matches. If it returns -1 then there is no such object with same name. In that case update the array.
const array = [{
id: 1,
name: 'a'
}, {
id: 2,
name: 'b'
}, {
id: 3,
name: 'c'
}, {
id: 4,
name: 'd'
}, {
id: 5,
name: 'e'
}];
let newObjToAdd = {
id: 1,
name: 'z'
};
let newObjNotToAdd = {
id: 1,
name: 'a'
}
function updateArray(obj) {
let k = array.findIndex((item) => {
return item.name === obj.name;
})
if (k === -1) {
array.push(obj)
} else {
console.log('Array contains object with this name')
}
}
updateArray(newObjToAdd);
console.log(array)
updateArray(newObjNotToAdd);
You don't need lodash for some. You get that with native JS too (ES6):
const array = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'},{id:4,name:'d'},{id:5,name:'e'}];
console.log(array.some(e => e.name === 'a'));
if (!array.some(e => e.name === 'z')) {
array.push({id: 5, name: 'z'});
}
console.log(array);
Doing this with lodash is few chars shorter but here is how you could do it with ES6 and Array.some:
const array = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }, { id: 4, name: "D" }, { id: 5, name: "C" }];
const maybeUpdate = (arr, obj) => {
if(!array.some(x => x.id == obj.id))
array.push(obj)
}
maybeUpdate(array, {id: 2, name: "F"}) // id exists wont insert
maybeUpdate(array, {id: 12, name: "F"}) // will insert
console.log(array)
Same idea with lodash and _.some would be:
const array = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }, { id: 4, name: "D" }, { id: 5, name: "C" }];
const maybeUpdate = (arr, obj) => {
if(!_.some(array, {id: obj.id}))
array.push(obj)
}
maybeUpdate(array, {id: 2, name: "F"}) // id exists wont insert
maybeUpdate(array, {id: 12, name: "F"}) // will insert
console.log(array)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Note that you could also use various other ways to get the same result. Array.find or _.find would work as well since all you have to do is to check if there was a hit:
const maybeUpdate = (arr, obj) => {
if(!_.find(array, {id: obj.id})) // or if(!array.find(x => x.id == obj.id))
array.push(obj)
}

Javascript map over array of obj with another array to get different key value

So I am not sure why I having such a difficult time with this, but I have an array of ids that I am trying to use to map over an array of objects to find the corresponding id but return the value from a different key.
i.e.:
arr=[13, 1, 16]
arrObj= [{
id: 1,
name: "cat"
}, {
id: 10,
name: "tiger",
}, {
id: 3,
name: "dog",
}, {
id: 16,
name: "bear",
}, {
id: 8,
name: "fish",
}, {
id: 13,
name: "goat",
}]
and I want it to return:
["goat", "cat", "bear"]
I have a nested map function that does this but returns undefined for the objects that do not have a corresponding ID. I could filter out the undefineds from the returned array, but it seems that there is a cleaner/more efficient way to do this.
What is the cleanest way to achieve this?
You could use Array#map and search with Array#find for the corresponding object. Then take name as return value.
var arr = [13, 1, 16],
arrObj = [{ id: 1, name: "cat" }, { id: 10, name: "tiger" }, { id: 3, name: "dog" }, { id: 16, name: "bear" }, { id: 8, name: "fish" }, { id: 13, name: "goat" }],
result = arr.map(id => arrObj.find(o => o.id === id).name);
console.log(result);
For a lots of data, you could take a Map and build it by mapping key value pairs and then map the result of the map.
var arr = [13, 1, 16],
arrObj = [{ id: 1, name: "cat" }, { id: 10, name: "tiger" }, { id: 3, name: "dog" }, { id: 16, name: "bear" }, { id: 8, name: "fish" }, { id: 13, name: "goat" }],
result = arr.map(
Map.prototype.get,
new Map(arrObj.map(({ id, name }) => [id, name]))
);
console.log(result);
Try this:
var arr=[13, 1, 16];
var arrObj= [{
id: 1,
name: "cat"
}, {
id: 10,
name: "tiger",
}, {
id: 3,
name: "dog",
}, {
id: 16,
name: "bear",
}, {
id: 8,
name: "fish",
}, {
id: 13,
name: "goat",
}];
var result = arr.map(id => arrObj.find(x => x.id == id)).map(x => x.name)
console.log(result);
// ["goat", "cat", "bear"]
.map() (from MDN web docs):
method creates a new array with the results of calling a provided
function on every element in the calling array.
.find() (from MDN web docs):
method returns the value of the first element in the array that
satisfies the provided testing function. Otherwise undefined is
returned.
There have been a lot of good answers already, however i feel the need to push for newer syntax as it is greater to work with in the long run.
const getNamesBasedOnIds = (arr, listOfIds) => {
return arr.reduce(((sum, element) =>
[...sum, ...(listOfIds.includes(element.id) ? [element.name] : [])]),
[]);
}
const animals = getNamesBasedOnIds(arrObj, [13,1,16]);
Using Array.filter, then Array.map requires you to run through the Array max twice.
With Array.reduce you can add elements to the sum if they exists in listOfIds, then after running through the arrObj once you have the result
[...sum, ...(listOfIds.includes(element.id) ? [element.name] : [])] is pretty slow, but its more for showing the use of spear operators
The above is equivalent to
sum.concat(listOfIds.includes(element.id) ? element.name : [])]
The fastest way, is to use Array.push
if(listOfIds.includes(element.id)){
sum.push(element.name);
}
return sum;
The correct way is to not nest any loops:
reduce your array of objects to a map of 'id-values' idValueMap
map through your array of 'ids' idArr using the idValueMap to get
the corresponding values for each id in constant time.
Thought Process
Understand that the biggest problem is the data itself. Don't let insufficient data types or structures force you you have a bad solution/code. Transform the data such to what you need so that you can create a proper solution.
Basically imagine if the objArr was just a Map that you could use to look up the values for an id.... then the solution is straight forward. So let's make that happen and then the rest falls into place. Data Data Data is what I always say :)
Rule of thumb NEVER run a loop inside of a loop if you can help it. FYI: filter, find, map, indexOf .... are all loops internally, do not nest them unless you absolutely must.
This solution is by far the most performant. This way you are not running O(n^2) (very BAD), you are instead running O(n) (very GOOD):
const idArr = [ 13, 1, 16 ];
const objArr= [
{
id: 1,
name: "cat"
},
{
id: 10,
name: "tiger",
},
{
id: 3,
name: "dog",
},
{
id: 16,
name: "bear",
},
{
id: 8,
name: "fish",
},
{
id: 13,
name: "goat",
}
];
const idValueMap = objArr.reduce((acc, { id, name }) => ({ ...acc, [id]: name }), {});
let output = idArr.map((id) => idValueMap[id]);
console.log(output);
You can first use .filter to filter and then use .map to output the desired properties
here
var arr = [13, 1, 16],
arrObj = [{
id: 1,
name: "cat"
}, {
id: 10,
name: "tiger",
}, {
id: 3,
name: "dog",
}, {
id: 16,
name: "bear",
}, {
id: 8,
name: "fish",
}, {
id: 13,
name: "goat",
}];
var res = arrObj.filter(o => arr.indexOf(o.id) >= 0);
console.log(res.map(o => o['name']))

Categories

Resources