How search two arrays and find if there is a match? - javascript

I have an array :
[{name:'blah',id:1},{name:'blah2',id:3}]
I have another array :
[{type:'blah',uid:3435},{type:'blah2',uid:3}]
I want to end up with :
[{newname:'blah2',uidid:3}]
You can see I want to match the two based on a mapping of id=uid. Really struggling to find a way to do this in js. I have underscore installed.

You could build a hash table with the first array and use it in the iteration of the second array.
var array1 = [{ name: 'blah', id: 1 }, { name: 'blah2', id: 3 }],
array2 = [{ type: 'blah', uid: 3435 }, { type: 'blah2', uid: 3 }],
hash = Object.create(null),
match = [];
array1.forEach(function (a) {
hash[a.id] = a;
});
array2.forEach(function (a) {
hash[a.uid] && match.push({ newname: a.type, uidid: a.uid });
});
console.log(match);

Since you are wanting an array with an object that uses different key names, something like this will work. It is also simple to read and to understand without any complex syntax or logic.
var arr1 = [{name: 'blah', id: 1}, {name: 'blah2', id: 3}];
var arr2 = [{type: 'blah', uid: 3435}, {type: 'blah2', uid: 3}];
var arr3 = [];
arr1.forEach(function(obj1, i) {
arr2.forEach(function(obj2) {
if (obj1.id == obj2.uid) {
arr3.push({newname: obj1.name, uidid: obj1.id})
}
})
});
console.log(arr3);

Related

Compare and update two arrays without losing mutated data

I have an array of objects contains data of persons
const oldArr = [
{
id: 1,
name: 'Alex',
},
{
id: 2,
name: 'John',
},
{
id: 3,
name: 'Jack',
}
]
then I add data to this array to each element where I end up with new key called money with value of 20 as the following
oldArr.map((el, index) => el.money = 20)
and the array becomes like this
...
{
id: 2,
name: 'John',
money: 20
},
...
Now, I have a new array with new data (new person) but missing the money I have added before. (careful person with id 2 is not there)
const newArr = [
{
id: 1,
name: 'Alex',
},
{
id: 3,
name: 'Jack',
},
{
id: 4,
name: 'Chris',
},
]
I want to update the old array with new data but also keep the mutated data, and I want the result to end up like this:
const result = [
{
id: 1,
name: 'Alex',
money: 20
},
{
id: 3,
name: 'Jack',
money: 20
},
{
id: 4,
name: 'Chris',
},
]
Thanks for the help.
Just a note: map creates a whole new array, it doesn't make sense to use it for just mutating the contents. Use forEach or just a regular for loop instead.
oldArr.forEach((el) => (el.money = 20));
The following will give you the intended result:
const result = newArr.map(
(newEl) => oldArr.find((el) => el.id === newEl.id) || newEl
);
The OR operator || returns the second argument if the first is falsey.
You can optimize this by mapping items by id instead of brute force searching the old array.
const idMap = new Map();
oldArr.forEach((el) => {
el.money = 20;
idMap.set(el.id, el);
});
const result = newArr.map((newEl) => idMap.get(newEl.id) || newEl);
Stackblitz: https://stackblitz.com/edit/js-f3sw8w?file=index.js
If I getted it clear you are just trying to iterate throw the items of array generating a new array with the property "money" added to each one.
If so the map is the best option, just assign it to a new variable and change the item before return the element like bellow.
const oldArr = [
{
id: 1,
name: "Alex"
},
{
id: 2,
name: "John"
},
{
id: 3,
name: "Jack"
}
];
const newArr = oldArr.map((el) => {
el.money = "20";
return el;
});
console.log(oldArr);
console.log(newArr);
In this way you'll be able to keep both arrays.
If wasn't this, pls let me know.
Just merge the objects:
const result = oldArr.map((person) => ({
...person,
...newArr.find((cur) => cur.id === person.id),
}));

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

JavaScript: How to add to values from an array to object properties which are from different array?

Where am I going wrong?
I was working on something. And I am facing this problem.
let array1 = [{
id: 1,
profile: ''
}, {
id: 2,
profile: ''
}, {
id: 3,
profile: ''
}]
let array2 = ['name1', 'name2', 'name3']
array1.forEach(function(value) {
for (let i = 0; i < array2.length; i++) {
return value['profile'] = array2[i]
}
})
console.log(array1);
required output:
array1 = [{id:1, profile: 'name1'}, {id:2, profile: 'name2'}, {id:3, profile: 'name3'}]
I tried below code:
array1.forEach(function(value) {
for(let i=0; i<array2.length; i++){
return value['profile'] = array2[i]
}
})
But I am getting the following output:
[ { id: 1, profile: 'name1' },
{ id: 2, profile: 'name1' },
{ id: 3, profile: 'name1' } ]
Please guide me!
By calling a for loop inside the forEach loop you are actually changing each array1 item profile properties multiple times. If you just want to use the same index to copy one value from one array to the other, the forEach method handler takes the current index as second argument. Here is an example:
let array1 = [{
id: 1,
profile: ''
}, {
id: 2,
profile: ''
}, {
id: 3,
profile: ''
}]
let array2 = ['name1', 'name2', 'name3']
array1.forEach(function(value, i) {
value['profile'] = array2[i]
})
console.log(array1);
he code you shared is confusing a couple of concepts up which may be leading to your problem.
Array.forEach does not take a return value
mutating existing variables often leads to bugs
you are also looping round the whole of the 2nd array and always setting array value 1 to the result.
instead, let's use .map to fix those issues.
const array1 = [{id:1, profile: ''}, {id:2, profile: ''}, {id:3, profile: ''}]
const array2 = ['name1', 'name2', 'name3']
const array3 = array1.map(function (array1Item, index) {
return {
...array1Item,
profile: array2[index],
};
});
here we are never mutating, or changing, existing data. Within the map we use ... to create a shallow-copy of the array item to ensure that array1 never changes. This makes the code easier to maintain and read in the future.
You must try this this will work for you
let array1 = [{id:1, profile: ''}, {id:2, profile: ''}, {id:3, profile: ''}]
let array2= ['name1', 'name2', 'name3']
array1 = array1.map((i , index) =>{
return i.profile=array2[index]
})
console.log(array1);

Remove an array element if one of the property contains certain values

I have following variable:
var data = [{id: '1', name: 'demo1'}, {id: '2', name: 'demo2'}, {id: '3', name: 'demo3'}]
Now I have another list of ids,
var lookFor = ["2", "3"];
Now, from data how will I remove the objects with id not available in the lookFor array of ids.
I tried with following
_.filter(data, function(item) {
return _.contains(lookFor, 'id');
});
Is there any other way?
Uhm consider the following?
var data = [{id: '1', name: 'demo1'}, {id: '2', name: 'demo2'}, {id: '3', name: 'demo3'}];
var keys = ["2", "3"];
let filteredArray = data.filter(element => keys.indexOf(element.id) != -1);
console.log(filteredArray);
// Output is now
// 0: {id: "2", name: "demo2"}
// 1: {id: "3", name: "demo3"}
Use this the get the opposite:
let filteredArray = data.filter(element => keys.indexOf(element.id) == -1);
console.log(filteredArray);
// Output is:
// 0: {id: "1", name: "demo1"}
Is that what you want?
Have a nice day, Elias
You can use functor filter for array and method includes to
determine whether an array includes a certain element
var res = data.filter(el=>!lookFor.includes(el.id));
result
[{id: "1", name: "demo1"}]
Opposite
var res = data.filter(el=>lookFor.includes(el.id));
You could use _.remove(array, [predicate=_.identity]) as following. Notice that this mutates the value of data.
var data = [{id: '1', name: 'demo1'}, {id: '2', name: 'demo2'}, {id: '3', name: 'demo3'}];
var lookFor = ["2", "3"];
_.remove(data, function(n) {
return _.indexOf(lookFor, n.id) === -1;
});
console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
Here are just a few examples of how you can achieve this with ES6 only or with lodash. There are obviously more ways to do it but those should give you an idea. Also note that most of the examples do not mutate the arrays utilized:
var data = [{id: '1', name: 'demo1'}, {id: '2', name: 'demo2'}, {id: '3', name: 'demo3'}]
var lookFor = ["2", "3"];
// Does not mutate the array and uses ES6 Filter
var withFilter = data.filter(x => lookFor.indexOf(x.id) >= 0)
// Does not mutate the array and uses ES6 Reduce
var withReduce = lookFor.reduce((r,c) => r.push(data.find(x => x.id === c) || []) && r,[])
// Does not mutate the array with Lodah Filter
var withLodashFilter = _.filter(data, x => _.includes(lookFor, x.id))
// Mutates the array with Lodash Remove
var withLodashRemove = _.remove(data, x => _.includes(lookFor, x.id))
console.log('ES6 Filter', withReduce)
console.log('ES6 Reduce', withFilter)
console.log('Lodah Filter', withLodashFilter)
console.log('Lodash Remove', withLodashRemove)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

JavaScript: How to Fetch a object from array of objects, given an id, without using for..in loop?

Let us assume that we have an array
var mRegions = [];
This array get's populated with following object
$.ajax(settings).done(function (response) {
for (var i in response.items[0].devices)
{
mRegions.push(
{
id: response.items[0].devices[i].id,
name: response.items[0].devices[i].name,
description: response.items[0].devices[i].description,
uid: response.items[0].devices[i].beacon.iBeacon.uid,
major: response.items[0].devices[i].beacon.iBeacon.major,
minor: response.items[0].devices[i].beacon.iBeacon.minor,
});
}
var myId = 'b1';
At some point of time, I need to get an object from this array of objects whose id matches with the given id (myID)
Is there a way to achieve this without a for...in loop?
Array.prototype.find(). Make sure you read the browser compatibility section.
myRegions.find(region => region.id === myId)
or the legacy version
myRegions.find(function(r){return r.id === myId})
let myRegions = [{
id: 'a1',
name: 'A 1'
}, {
id: 'a2',
name: 'A 2'
}, {
id: 'a3',
name: 'A 3'
}, {
id: 'b1',
name: 'B 1'
}, {
id: 'b2',
name: 'B 2'
}];
let myId = 'b1';
let pre = document.createElement('pre');
pre.textContent = JSON.stringify(myRegions.find(region => region.id === myId), null, ' ');
document.body.appendChild(pre);
If it is an option, you can use an object istead of an array, and set the keys as ids.
var mRegions = {};
$.ajax(settings).done(function (response) {
for (var i in response.items[0].devices) {
mRegions[response.items[0].devices[i].id] = {
id: response.items[0].devices[i].id,
name: response.items[0].devices[i].name,
description: response.items[0].devices[i].description,
uid: response.items[0].devices[i].beacon.iBeacon.uid,
major: response.items[0].devices[i].beacon.iBeacon.major,
minor: response.items[0].devices[i].beacon.iBeacon.minor,
};
}
});
Then access the values with the following notation:
var region = mRegions.theId
Or:
var myId = 123;
var region = mRegions[myId];
let array = [
{id: 1, name: 'Name1'},
{id: 3, name: 'Name3'},
{id: 5, name: 'Name5'},
{id: 7, name: 'Name7'}
];
let result = array.filter(function( obj ) {
return obj.id === 5;
});
Also consider .find() function from #Phil answer.
.filter definition:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
.find definition:
The find() method returns a value in the array, if an element in the
array satisfies the provided testing function. Otherwise undefined is
returned.

Categories

Resources