JavaScript - Changing the value of object literals - javascript

guys!
Basically I want to replace the object literal "title" value of all objects within arr2 with each of the elements within arr1.
const arr1 = ['first', 'second', 'third']
const arr2 = [
{
id: 1,
title: 'hello'
},
{
id: 2,
title: 'world'
},
{
id: 3,
title: ' 🌎'
}
]
For the end result to be this:
const final = [
{
id: 1,
title: 'first'
},
{
id: 2,
title: 'second'
},
{
id: 3,
title: 'third'
}
]
I really don't understand how I could do such a thing, I am totally stranded at this stage.
Have a great day!

You can clone your original object (to avoid mutation) and then iterates with a for loop replacing every object inside the array:
const arr1 = ['first', 'second', 'third']
const arr2 = [
{
id: 1,
title: 'hello'
},
{
id: 2,
title: 'world'
},
{
id: 3,
title: ' 🌎'
}
]
let result = JSON.parse(JSON.stringify(arr2));
for(let i = 0; i < arr2.length; i++){
result[i].title = arr1[i]
}
console.log(result)

You can do like as follows:
arr2.forEach((x,i)=>{x.title=arr1[i]})
x : is element
i : is index
Example:
var arr1 = ['first', 'second', 'third']
var arr2 = [
{
id: 1,
title: 'hello'
},
{
id: 2,
title: 'world'
},
{
id: 3,
title: ' 🌎'
}
]
arr2.forEach((x,i)=>{x.title=arr1[i]})
console.log(arr2)
if you don't want to modify existing object you can use map method
arr2.map((x,i)=>{
return {id:x.id,title:arr1[i]}
})
Example:
var arr1 = ['first', 'second', 'third']
var arr2 = [
{
id: 1,
title: 'hello'
},
{
id: 2,
title: 'world'
},
{
id: 3,
title: ' 🌎'
}
]
var result = arr2.map((x,i)=>{
return {id:x.id,title:arr1[i]}
})
console.log(result)

arr2.map((v, k) =>{
v.title = arr1[k]
});
You set the title of each item with the string in the arr1 which is at the same index.

Related

Compare two arrays of objects, and remove if object value is equal

I've tried modifying some of the similar solutions on here but I keep getting stuck, I believe I have part of this figured out however, the main caveat is that:
Some of the objects have extra keys, which renders my object comparison logic useless.
I am trying to compare two arrays of objects. One array is the original array, and the other array contains the items I want deleted from the original array. However there's one extra issue in that the second array contains extra keys, so my comparison logic doesn't work.
An example would make this easier, let's say I have the following two arrays:
const originalArray = [{id: 1, name: "darnell"}, {id: 2, name: "funboi"},
{id: 3, name: "jackson5"}, {id: 4, name: "zelensky"}];
const itemsToBeRemoved = [{id: 2, name: "funboi", extraProperty: "something"},
{id: 4, name: "zelensky", extraProperty: "somethingelse"}];
after running the logic, my final output should be this array:
[{id: 1, name: "darnell"}, {id: 3, name: "jackson5"}]
And here's the current code / logic that I have, which compares but doesn't handle the extra keys. How should I handle this? Thank you in advance.
const prepareArray = (arr) => {
return arr.map((el) => {
if (typeof el === "object" && el !== null) {
return JSON.stringify(el);
} else {
return el;
}
});
};
const convertJSON = (arr) => {
return arr.map((el) => {
return JSON.parse(el);
});
};
const compareArrays = (arr1, arr2) => {
const currentArray = [...prepareArray(arr1)];
const deletedItems = [...prepareArray(arr2)];
const compared = currentArray.filter((el) => deletedItems.indexOf(el) === -1);
return convertJSON(compared);
};
How about using filter and some? You can extend the filter condition on select properties using &&.
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
console.log(
originalArray.filter(item => !itemsToBeRemoved.some(itemToBeRemoved => itemToBeRemoved.id === item.id))
)
Or you can generalise it as well.
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
function filterIfSubset(originalArray, itemsToBeRemoved) {
const filteredArray = [];
for (let i = 0; i < originalArray.length; i++) {
let isSubset = false;
for (let j = 0; j < itemsToBeRemoved.length; j++) {
// check if whole object is a subset of the object in itemsToBeRemoved
if (Object.keys(originalArray[i]).every(key => originalArray[i][key] === itemsToBeRemoved[j][key])) {
isSubset = true;
}
}
if (!isSubset) {
filteredArray.push(originalArray[i]);
}
}
return filteredArray;
}
console.log(filterIfSubset(originalArray, itemsToBeRemoved));
Another simpler variation of the second approach:
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
const removeSubsetObjectsIfExists = (originalArray, itemsToBeRemoved) => {
return originalArray.filter(item => {
const isSubset = itemsToBeRemoved.some(itemToBeRemoved => {
return Object.keys(item).every(key => {
return item[key] === itemToBeRemoved[key];
});
});
return !isSubset;
});
}
console.log(removeSubsetObjectsIfExists(originalArray, itemsToBeRemoved));
The example below is a reusable function, the third parameter is the key to which you compare values from both arrays.
Details are commented in example
const arr=[{id:1,name:"darnell"},{id:2,name:"funboi"},{id:3,name:"jackson5"},{id:4,name:"zelensky"}],del=[{id:2,name:"funboi",extraProperty:"something"},{id:4,name:"zelensky",extraProperty:"somethingelse"}];
/** Compare arrayA vs. delArray by a given key's value.
--- ex. key = 'id'
**/
function deleteByKey(arrayA, delArray, key) {
/* Get an array of only the values of the given key from delArray
--- ex. delList = [1, 2, 3, 4]
*/
const delList = delArray.map(obj => obj[key]);
/* On every object of arrayA compare delList values vs
current object's key's value
--- ex. current obj[id] = 2
--- [1, 2, 3, 4].includes(obj[id])
Any match returns an empty array and non-matches are returned
in it's own array.
--- ex. ? [] : [obj]
The final return is a flattened array of the non-matching objects
*/
return arrayA.flatMap(obj => delList.includes(obj[key]) ? [] : [obj]);
};
console.log(deleteByKey(arr, del, 'id'));
let ff = [{ id: 1, name: 'darnell' }, { id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' }]
let cc = [{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' }]
let ar = []
let out = []
const result = ff.filter(function(i){
ar.push(i.id)
cc.forEach(function(k){
out.push(k.id)
})
if(!out.includes(i.id)){
// console.log(i.id, i)
return i
}
})
console.log(result)

Filter complex array by another array

let array1 = [
{
id: 1,
genres: [
{ id: 4, title: "qqqq" },
{ id: 9, title: "zzzz" },
{ id: 8, title: "eeee" },
],
},
{
id: 2,
genres: [
{ id: 2, title: "qwert" },
{ id: 4, title: "asdf" },
{ id: 5, title: "zxxcc" },
],
},
];
let array2 = [6, 8];
I need to filter array1 if genre id exists in array2.
So in output I should have only first element of array1.
How to do that?
You can use a combination of filter, some and includes:
let array1 = [{id:1,genres:[{id:4,title:"qqqq" },{id:9,title:"zzzz"},{id:8,title:"eeee" }]},
{id:2,genres:[{id:2,title:"qwert"},{id:4,title:"asdf"},{id:5,title:"zxxcc"}]}];
let array2 = [6, 8];
let result = array1.filter(({genres}) => genres.some(({id}) => array2.includes(id)));
console.log(result);
Use the filter function.
One way to do it:
let result = array1.filter(el => {
let output = false;
el.genres.forEach( genre => {
if (array2.includes(genre.id))
output = true;
});
return output;
});

How to filter an array of object with an array of numbers

Given an array of objects arr1 how can I filter out to a new array the objects that do not have a property equal to any value in the array of numbers arr2
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
// Failed attempt
const newArr = arr1.filter(obj1 => arr2.some(num1 => num1 !== obj1.key))
console.log(newArr)
// Expected: [{ key: 1, name: 'Al' }]
// Received: [
// { key: 1, name: 'Al' },
// { key: 2, name: 'Lo' },
// { key: 3, name: 'Ye' }
// ]
Using your syntax:
You have to match on the somein case it's the same and not different. Then if it matches, do not keep the value.
const arr1 = [
{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr= arr1.filter(x => !arr2.some(y => y === x.key));
console.log(newArr);
Alternative syntax below :
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.some(y => y === key));
console.log(newArr);
That said, you should be using Array.includes() like some ppl answered. It's simplier for the same outcome
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.includes(key));
console.log(newArr);
You can do this
const newArr = arr1.filter(obj => !arr2.includes(obj.key));
This will work for you:
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const filtered = arr1.filter(val => !arr2.includes(val.key))
console.log(filtered)
:)
For situations like this Set is also very cool (and for big arrays more performant):
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const arr2Set = new Set(arr2);
const newArr = arr1.filter(obj1 => !arr2Set.has(obj1.key))
console.log(newArr)
You can use indexOf like this:
const newArr = arr1.filter(obj => arr2.indexOf(obj.key) > -1);
You need to filter the arr1 when arr1 element does not exist in arr2, so I think it could be better to use indexOf() like this
const newArr = arr1.filter(obj1 => arr2.indexOf(obj1.key) === -1)
if the element does not exist in arr2 it will return -1 which what you need.

JavaScript filter array by data from another

I have an array object:
[
{ id:1, name: 'Pedro'},
{ id:2, name: 'Miko'},
{ id:3, name: 'Bear'},
{ id:4, name: 'Teddy'},
{ id:5, name: 'Mouse'}
]
And I have an array with ids [1, 3, 5],
How can I filter the array object to leave records only with id's from the second one?
If Array.includes() is supported, you can use it with Array.filter() to get the items:
const array = [
{ id: 1, name: 'Pedro'},
{ id: 2, name: 'Miko'},
{ id: 3, name: 'Bear'},
{ id: 4, name: 'Teddy'},
{ id: 5, name: 'Mouse'}
];
const filterArray = [1,3,5];
const result = array.filter(({ id }) => filterArray.includes(id));
console.log(result);
If includes is not supported, you can use Array.indexOf() instead:
var array = [
{ id: 1, name: 'Pedro'},
{ id: 2, name: 'Miko'},
{ id: 3, name: 'Bear'},
{ id: 4, name: 'Teddy'},
{ id: 5, name: 'Mouse'}
];
var filterArray = [1,3,5];
var result = array.filter(function(item) {
return filterArray.indexOf(item.id) !== -1;
});
console.log(result);
Maybe take a Array.prototype.reduce in combination with an Array.prototype.some. This keeps the order of the given array need.
var data = [
{ id: 3, name: 'Bear' },
{ id: 4, name: 'Teddy' },
{ id: 5, name: 'Mouse' },
{ id: 1, name: 'Pedro' },
{ id: 2, name: 'Miko' },
],
need = [1, 3, 5],
filtered = need.reduce(function (r, a) {
data.some(function (el) {
return a === el.id && r.push(el);
});
return r;
}, []);
document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');
To keep the order of data you can use Array.prototype.filter:
var data = [
{ id: 3, name: 'Bear' },
{ id: 4, name: 'Teddy' },
{ id: 5, name: 'Mouse' },
{ id: 1, name: 'Pedro' },
{ id: 2, name: 'Miko' },
],
need = [1, 3, 5],
filtered = data.filter(function (a) {
return ~need.indexOf(a.id);
});
document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');
In case the data set is small, you are ok with any of the offered solution (ones that use indexOf).
However, these solutions are O(n^2) ones, therefore, given the data set big enough, the lag can become noticeable. In this case, you should build an index prior to selecting elements.
Example:
function filterFast(data, ids) {
var index = ids.reduce(function(a,b) {a[b] = 1; return a;}, {});
return data.filter(function(item) {
return index[item.id] === 1;
});
}
And some benchmarking can be tested here.
You can use the filter method on your Array:
var data = [
{ id:1, name: 'Pedro'},
{ id:2, name: 'Miko'},
{ id:3, name: 'Bear'},
{ id:4, name: 'Teddy'},
{ id:5, name: 'Mouse'}
];
var ids = [1, 3, 5];
var filteredData = filterData(data, 'id', ids[1]);
function filterData(data, prop, values) {
return data.filter(function(item) {
return ~values.indexOf(item[prop]); // ~ returns 0 if indexOf returns -1
});
}
See it in action in this JSFiddle.
Or if you are using jQuery, another option may be:
var arr1 = [1, 3, 5],
arr2 = [{ id: 1, name: 'Pedro' },
{ id: 2, name: 'Miko' },
{ id: 3, name: 'Bear' },
{ id: 4, name: 'Teddy' },
{ id: 5, name: 'Mouse' }],
filtered = $.grep(arr2, function (item) {
if (arr1.indexOf(item.id) > -1) {
return true;
}
});
You can use a for loop on the object array and check hasOwnProperty in another for loop for each ids in [1,3,5] (break out of the loop once an id found). (And break out of the bigger for-loop once all ids are found) If your array object is ordered (e.g. elements sorted from smallest id to biggest id) and so are your list, this solution should be quite efficient.
var c = 0;
for(var i =0; i< objects.length; i++){
for(var v =0; v< list.length; v++)
if(objects[i].hasOwnProperty(list[v])){
delete objects[i]; c++; break;
}
if(c===list.length) break;
}
or use array.splice( i, 1 ); if you don't want an empty slot.
Using filter and indexOf will do the trick:
var filteredArray = dataArray.filter(function(obj) {
return idsArray.indexOf(obj.id) > -1;
});
However, indexOf has linear performance, and it will be called lots of times.
In ES6 you can use a set instead, whose has call has sublinear performance (on average):
var idsSet = new Set(idsArray),
filteredArray = dataArray.filter(obj => idsSet.has(obj.id));
Assuming the toString method of your ids is injective, you can achieve something similar in ES5:
var idsHash = Object.create(null);
idsArray.forEach(function(id) {
idsHash[id] = true;
});
var filteredArray = dataArray.filter(function(obj) {
return idsHash[obj.id];
});

Find and update an object in an array

I want to get an object from an array of objects, then update it.
var myObjs = [{ id: 1, name: "foo"}, { id: 2, name: "bar" }];
var myObjectToUpdate = _.findWhere(myObjs, { id: 2 });
myObjectToUpdate = { id: 2, name: "boop" };
myObjs[1] // { id: 2, name: "boop" }
Currently when I update myObject in the 3rd line, it does not update the array of objects. I'm assuming it is updating the new variable instead of referencing.
What is the correct way to do this?
#E_net4 is correct, you are reassigning the object you just found.
If all you need to do is update the name, try this:
var myObjs = [{ id: 1, name: "foo"}, { id: 2, name: "bar" }];
var myObjectToUpdate = _.findWhere(myObjs, { id: 2 });
myObjectToUpdate.name = "boop";
myObjs[1] // { id: 2, name: "boop" }
I guess this is what you want. You have, in your code, misconceptions. Please read my code and compare both.
Hope it helps!
function fn(arr, toReplace, newValue) {
for(var x in arr) {
for(var k in toReplace) {
if(arr[x][k] == toReplace[k]) {
arr[x] = newValue;
}
}
}
return arr;
};
var arr = [{ id: 1, name: "foo"}, { id: 2, name: "bar" }];
var newValue = {id: 2, name: "boop"};
arr = fn(arr, {id: 2}, newValue);
console.log(arr);

Categories