Javascript merge arrays when one contains updated data - javascript

I have two arrays of objects like this:
var myArray = [
{pk: '1', person: 'person 1'},
{pk: '2', person: 'someone'},
];
var updatedArray = [
{pk: '2', person: 'another person'}
];
I'm looking to merge the two in the most efficient way possible.
My thought was to merge the older myArray into the newer updatedArray and leave out any items where myArray.pk == updatedArray.pk
I'm having trouble trying to get it going with either jQuery or underscore.
I've been trying to use this one as an example as well.
Any ideas?

I think looping through updates and copy it over to current value would be a good way.
If you have just one property to change then there is no need for Object.assign. you can simply replace it with
myArray[idx].name = uv.name
var myArray = [
{pk: '1', person: 'person 1'},
{pk: '2', person: 'someone'},
];
var updatedArray = [
{pk: '2', person: 'another person'}
];
updatedArray.forEach(uv => {
var idx = myArray.findIndex(v => v.pk === uv.pk)
if (idx != -1)
myArray[idx] = Object.assign({}, myArray[idx], uv);
else myArray.push(uv);
});
console.log(myArray)

You can try
function mergeArr(arrOne, arrTwo, prop) {
_.each(arrTwo, function(arrTwoobj) {
var arrOneobj = _.find(arrOne, function(arrOneobj) {
return arrOneobj[prop] === arrTwoobj[prop];
});
arrOneobj ? _.extend(arrOneobj, arrTwoobj) : arrOne.push(arrTwoobj);
});
}
var myArray = [
{pk: '1', person: 'person 1'},
{pk: '2', person: 'someone'},
];
var updatedArray = [
{pk: '2', person: 'another person'}
];
mergeArr(myArray, updatedArray, 'pk');
console.log(myArray);

var myArray = [
{pk: '1', person: 'person 1'},
{pk: '2', person: 'someone'},
];
var updatedArray = [
{pk: '2', person: 'another person'}
];
var exists = [];
for (item of updatedArray) {
exists[item.pk] = true;
}
for (item of myArray) {
if (!exists.hasOwnProperty(item.pk)) {
updatedArray.push(item);
}
}
console.log(updatedArray);

Most efficient way would be, first create a map from one of the arrays.
Then run one loop and get the items from the map
you need just two functions, reduce and map
This way only need array1.length + array2.length iterations, not array1.length * array2.length
// creates the map
var myMap = myArray.reduce(function(obj, item) {
obj[item.pk] = item
}, {})
// merges updatedArray items, with the item from the map
var mergedArray = updatedArray.map(function(item) {
return myMap[item.pk] ? Object.assign({}, myMap[item.pk], item) : item
})

Related

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

Filter array of objects by another array with duplicate keys

I have this array of objects:
const data = [
{
id: 1,
name: 'Name1',
encryptionKey: 'AAA'
},
{
id: 2,
name: 'Name2',
encryptionKey: 'BBB'
},
{
id: 3,
name: 'Name3',
encryptionKey: 'CCC'
}
]
and another array of encryption keys:
const encryptionKeys = ['AAA', 'BBB']
I am then filtering the data array based on the encryptionKeys array like this:
var filtered = data.filter(function(item) {
return encryptionKeys.indexOf(item.encryptionKey) !== -1;
});
which works and filters the objects and saves them in a new array. The problem is however if the encryptionKey array has duplicated keys, for example:
const encryptionKeys = ['AAA', 'BBB', 'BBB']
then all duplicate keys will be ignored and the filtered array will only have, in this case, 2 objects instead of 3. What am I doing wrong in my filtering code? The filtered array should have duplicate objects if the encryptionKeys array has duplicate values.
Make note of .flat() 's Browser compatibility and then see #babel/polyfill
const data = [
{
id: 1,
name: 'Name1',
encryptionKey: 'AAA'
},
{
id: 2,
name: 'Name2',
encryptionKey: 'BBB'
},
{
id: 3,
name: 'Name3',
encryptionKey: 'CCC'
}
]
const keys = ['AAA', 'BBB', 'BBB', 'AAA', 'BBB', 'ZZZ']
const occurances = data.map(d => {
const { encryptionKey } = d
const keyedOccurances = keys
.filter(k => k === encryptionKey)
.map(k => encryptionKey === k && d)
return keyedOccurances.length && keyedOccurances
})
.filter(Boolean)
.flat()
console.log(occurances)
Easy - just use filter on encryptionKeys beforehand:
var filtered = data.filter(function(item) {
return encryptionKeys.filter((e, i, a) => a.indexOf(e) == i).indexOf(item.encryptionKey) !== -1;
});
Alternatively, make an Array from a Set:
var filtered = data.filter(function(item) {
return [...new Set(encryptionKeys)].indexOf(item.encryptionKey) !== -1;
});
Make your encryption keys unique before you compare and filter it.
var encryptionKeys = ['AAA', 'BBB', 'BBB'];
var unique = encryptionKeys.filter((v, i, a) => a.indexOf(v) === i);
console.log(unique);
You could map the wanted items.
const
data = [{ id: 1, name: 'Name1', encryptionKey: 'AAA' }, { id: 2, name: 'Name2', encryptionKey: 'BBB' }, { id: 3, name: 'Name3', encryptionKey: 'CCC' }],
encryptionKeys = ['AAA', 'BBB', 'BBB'],
result = encryptionKeys.map(key => data.find(o => o.encryptionKey === key));
console.log(result);
A short approach with a Map and filtering the keys in advance.
const
data = [{ id: 1, name: 'Name1', encryptionKey: 'AAA' }, { id: 2, name: 'Name2', encryptionKey: 'BBB' }, { id: 3, name: 'Name3', encryptionKey: 'CCC' }],
encryptionKeys = ['AAA', 'BBB', 'BBB', 'DDD'],
map = new Map(data.map(o => [o.encryptionKey, o])),
result = encryptionKeys
.filter(Map.prototype.has, map)
.map(Map.prototype.get, map);
console.log(result);

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>

Check and get data from an array in JavaScript

I have an object:
var Obj1 = {id: 1, name: 'Apple'}
And an array object:
var ArrObj = [ {id: 1, name: 'Apple', 'eat': 'rice}, {'id: 2', 'name': 'Banana'}]
How do I check Obj1.id in ArrObj? And I want the result to be: { id:1, name: 'Apple', 'eat':'rice'}
You can use Array.find():
var Obj1 = {id: 2, name: 'Banana'}
var ArrObj = [ {id: 1, name: 'Apple', 'eat': 'rice'}, {'id': 2, 'name': 'Banana'}];
var res = ArrObj.find(({id}) => id === Obj1.id );
console.log(res);
You can also use array destructuring way like:
var Obj1 = {id: 2, name: 'Banana'}
var ArrObj = [ {id: 1, name: 'Apple', 'eat': 'rice'}, {'id': 2, 'name': 'Banana'}];
var res = ArrObj.find(({id}) => id === Obj1.id);
console.log(res);
You could also use the filter function like this:
let result = ArrObj.filter(obj => {
return obj.id == Obj1.id
})
Documentation is here: Array.prototype.filter()
all right!
you can also add array and get it by code :
var obj = '{ "name" : "amr" , "age" : "16"}';
var obj1 = JSON.parse(obj);
alert("yourname is : "+obj1.name+" , your age is "+obj1.age);
// it get name > amr and age > 16
it's very easy :)

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

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

Categories

Resources