How to change value in array with objects in JS - javascript

I have an array and want to change name in object { id: 4, name: 'name4' } to 'name6'
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
},
I try in this way but it isn't working
const name = 'name4';
const result = example?.forEach((group) =>
group.items.forEach((item) =>
if (item.name === name) {
return item.name === 'name6';
}
return null;
})
);

The for...of statement is my recommendation for readability and loop optimisation.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' },
],
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' },
],
},
];
const oldName = 'name4';
const newName = 'name6';
for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break
}
}
}
You could even go a step further and terminate the outer loop with a label if you only need to change the name in a single group.
outerLoop: for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break outerLoop;
}
}
}
Hope this helps.

You could either change the value by simply assigning a new value.
example[1].items[0].name = 'name6'
But you can also iterate through all items and search for the name you want to change. I created a function that goes through an array and loops over its nested items arrays searching for any given name (targetName) and replacing it with a new one (newName):
function changeName(array, targetName, newName) {
// Loop through the elements of array
array.forEach((element) => {
// Check each item: change the name if it matches the target
element.items.forEach((item) => {
if (item.name === targetName) item.name = newName;
});
});
}
// This function will check example array and change
// every name that has a value 'name4' into 'name6'
changeName(example, "name4", "name6");

forEach doesn't return any value.
Instead of return item.name === 'name6' you can simply set new value to item.name.

Why not like this?
const example = [{
id: '1234',
desc: 'sample1',
items: [{
id: 1,
name: 'name1'
},
{
id: 2,
name: 'testItem2'
}
]
},
{
id: '3456',
desc: 'sample2',
items: [{
id: 4,
name: 'name4'
},
{
id: 5,
name: 'testItem5'
}
]
},
]
example[1].items[0].name = 'name6'
console.log(example)

Related

How to deep filter in array with objects in JS

I have an array and want to get just object { id: 4, name: 'name4' },
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
},
I try in this way.
const name = 'name4';
example.forEach((item) => item.items.find((i) => i.name === name));
But get undefined.
You can using flatMap() to do it
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
}]
const name = 'name4';
let result = example.flatMap(e => e.items).filter(d => d.name == name)
console.log(result)
this way...?
const example =
[ { id : '1234'
, desc : 'sample1'
, items:
[ { id: 1, name: 'name1' }
, { id: 2, name: 'testItem2' }
] }
, { id : '3456'
, desc : 'sample2'
, items:
[ { id: 4, name: 'name4' }
, { id: 5, name: 'testItem5' }
] } ];
const rechName = (s,arr) =>
arr.find( x => // find the first parent object
x.items.some( y => // containing the search
y.name === s )
)?.items // if one
.find( z => z.name === s ); // find it in!
console.log( rechName('name4', example) ) // -> { id: 4, name: 'name4' }
console.log( rechName('abc', example) ) // -> undefined
forEach doesn't do what you think it does. From the docs:
The forEach() method executes a provided function once for each array element.
...
Return value
undefined.
So if you want to use forEach you need to save the value:
const example =
[ { id : '1234'
, desc : 'sample1'
, items:
[ { id: 1, name: 'name1' }
, { id: 2, name: 'testItem2' }
] }
, { id : '3456'
, desc : 'sample2'
, items:
[ { id: 4, name: 'name4' }
, { id: 5, name: 'testItem5' }
] } ]
const results = []; // Store matches here
const name = 'name4';
example.forEach((item) => {
const res = item.items.find((i) => i.name === name);
if (res !== undefined) {
results.push(res);
}
});
console.log(results);
IMHO I would suggest a more functional approach using flatMap and filter instead of forEach.
Lastly, note that in my above snippet, I'm storing the results in an array as it's not entirely clear to me that you won't have multiple matches per your example. But if you're sure that you will only ever have one result then a simple for loop works better, especially if you have a large array of items:
let result = null;
for (let i = 0; i < example.length; i++) {
const res = example[i].items.find((j) => j.name === name);
if (res !== undefined) {
result = res;
break; // No need to iterate further
}
}
console.log(result);
You could use a recursive search function. Here's a detailed example:
// Applies the function recursively from the top of the data tree ("depth-first")
const
data = getData(),
id = 4,
result = findById(data, id);
console.log(result ?? `No item with id ${id} found`);
// Defines the function
function findById(haystack, needleId){
let needle = null; // Defaults to null if no match at or below this level
// Iterates through all the items at this level
for(const item of haystack){
if(item.id == needleId){
// Qapla': Quits early, passes honorable item up to previous level
needle = item;
return needle;
}
else {
// Checks children, grandchildren, etc, before continuing iteration
const nextHaystack = item.items;
if(nextHaystack?.length){
needle = findById(nextHaystack, needleId); // Recursive call
}
}
// Done searching children, continues to next iteration at this level
}
// Done searching this level, returns result up to previous level
return needle;
}
// Gets the initial data
function getData(){
return [
{
id: '1234',
desc: 'sample1',
items: [ { id: 1, name: 'name1' }, { id: 2, name: 'testItem2' } ]
},
{
id: '3456',
desc: 'sample2',
items: [ { id: 4, name: 'name4' }, { id: 5, name: 'testItem5' } ]
}
];
}

How to change object value in array with objects with if/else in JS

I have an array with objects. I need to find item with current name and change it.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,
]
},
{
id: '3456',
desc: 'sample2',
items: [
itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,
]
},
I try to do in this way, but it's not working.
I get construction like (5) 
[Array(1), Array(1)]
instead of 
[{…}, {…}]
const findName = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name === changedName;
return null;
})
)
);
}
findName('name1', 'name2')
let findName1 = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name = changedName;
return null;
})
)
);
}
This will work with following object (your object declaration seems to be wrong)
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,}
]
},
{
id: '3456',
desc: 'sample2',
items: [
{itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,}
]
}]

compare two arrays in javascript and delete the object that both arrays have

I have 2 arrays:
0: {id: 2, name: "TMA"}
1: {id: 3, name: "Hibbernate"}
0: {id: 1, name: "FB.DE"}
1: {id: 2, name: "TMA"}
2: {id: 3, name: "Hibbernate"}
3: {id: 4, name: "Event.it A"}
4: {id: 5, name: "Projket 2"}
5: {id: 6, name: "Projekt 1"}
I want to compare them and delete the objects with the id 2 and 3 cause both arrays have them and thats the similarity.
This is my Code so far:
const projectListOutput = projectsOfPersonArray.filter(project => data.includes(project));
console.log(projectListOutput);
But every time i run this projectListOutput is empty.
When using includes dont compare objects, Just build data as array of strings. Remaining code is similar to what you have.
arr1 = [
{ id: 2, name: "TMA" },
{ id: 3, name: "Hibbernate" },
];
arr2 = [
{ id: 1, name: "FB.DE" },
{ id: 2, name: "TMA" },
{ id: 3, name: "Hibbernate" },
{ id: 4, name: "Event.it A" },
{ id: 5, name: "Projket 2" },
{ id: 6, name: "Projekt 1" },
];
const data = arr1.map(({ id }) => id);
const result = arr2.filter(({ id }) => !data.includes(id));
console.log(result);
Your data array probably does not contain the exact same object references than projectsOfPersonArray. Look at the code below:
[{ foo: 'bar' }].includes({ foo: 'bar' });
// false
Objects look equal, but they don't share the same reference (= they're not the same).
It's safer to use includes with primitive values like numbers or strings. You can for example check the ids of your objects instead of the full objects.
You compare different objects, so every object is unique.
For filtering, you need to compare all properties or use a JSON string, if the order of properties is equal.
var exclude = [{ id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }],
data = [{ id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }, { id: 1, name: "FB.DE" }, { id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }, { id: 4, name: "Event.it A" }, { id: 5, name: "Projket 2" }, { id: 6, name: "Projekt 1" }],
result = data.filter(project =>
!exclude.some(item => JSON.stringify(item) === JSON.stringify(project))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do something similar to the next:
const source = [{
id: 1,
name: "FB.DE"
},
{
id: 2,
name: "TMA"
},
{
id: 3,
name: "Hibbernate"
},
{
id: 4,
name: "Event.it A"
},
{
id: 5,
name: "Projket 2"
},
{
id: 6,
name: "Projekt 1"
}
]
const toRemove = [{
id: 2,
name: "TMA"
},
{
id: 3,
name: "Hibbernate"
}
]
/**create object where keys is object "id" prop, and value is true**/
const toRemoveMap = toRemove.reduce((result, item) => ({
...result,
[item.id]: true
}), {})
const result = source.filter(item => !toRemoveMap[item.id])
You can make function from it:
function removeArrayDuplicates (sourceArray, duplicatesArray, accessor) {
const toRemoveMap = duplicatesArray.reduce((result, item) => ({
...result,
[item[accessor]]: true
}), {});
return sourceArray.filter(item => !toRemoveMap[item[accessor]])
}
removeArrayDuplicates(source, toRemove, 'id')
Or even better, you can make it work with a function instead of just property accessor:
function removeDuplicates (sourceArray, duplicatesArray, accessor) {
let objectSerializer = obj => obj[accessor];
if(typeof accessor === 'function') {
objectSerializer = accessor;
}
const toRemoveMap = duplicatesArray.reduce((result, item) => ({
...result,
[objectSerializer(item)]: true
}), {});
return sourceArray.filter(item => !toRemoveMap[objectSerializer(item)])
}
removeDuplicates(source, toRemove, (obj) => JSON.stringify(obj))
This function will help you merge two sorted arrays
var arr1 = [
{ id: 2, name: 'TMA' },
{ id: 3, name: 'Hibbernate' },
]
var arr2 = [
{ id: 1, name: 'FB.DE' },
{ id: 2, name: 'TMA' },
{ id: 3, name: 'Hibbernate' },
{ id: 4, name: 'Event.it A' },
{ id: 5, name: 'Projket 2' },
]
function mergeArray(array1, array2) {
var result = []
var firstArrayLen = array1.length
var secondArrayLen = array2.length
var i = 0 // index for first array
var j = 0 // index for second array
while (i < firstArrayLen || j < secondArrayLen) {
if (i === firstArrayLen) { // first array doesn't have any other members
while (j < secondArrayLen) { // we copy rest members of first array as a result
result.push(array2[j])
j++
}
} else if (j === secondArrayLen) { // second array doesn't have any other members
while (i < firstArrayLen) { // we copy the rest members of the first array to the result array
result.push(array1[i])
i++
}
} else if (array1[i].id < array2[j].id) {
result.push(array1[i])
i++
} else if (array1[i].id > array2[j].id) {
result.push(array2[j])
j++
} else {
result.push(array1[i])
i++
j++
}
}
return result
}
console.log(mergeArray(arr1,arr2));

Removing duplicate array values and then storing them [react]

I'm trying to strip the duplicate array values from my current array. And I'd like to store the fresh list (list without duplicates) into a new variable.
var names = ["Daniel","Lucas","Gwen","Henry","Jasper","Lucas","Daniel"];
const uniqueNames = [];
const namesArr = names.filter((val, id) => {
names.indexOf(val) == id; // this just returns true
});
How can I remove the duplicated names and place the non-duplicates into a new variable?
ie: uniqueNames would return...
["Daniel","Lucas","Gwen","Henry","Jasper"]
(I'm using react jsx) Thank you!
You can do it in a one-liner
const uniqueNames = Array.from(new Set(names));
// it will return a collection of unique items
Note that #Wild Widow pointed out one of your mistake - you did not use the return statement. (it sucks when we forget, but it happens!)
I will add to that that you code could be simplified and the callback could be more reusable if you take into account the third argument of the filter(a,b,c) function - where c is the array being traversed. With that said you could refactor your code as follow:
const uniqueNames = names.filter((val, id, array) => {
return array.indexOf(val) == id;
});
Also, you won't even need a return statement if you use es6
const uniqueNames = names.filter((val,id,array) => array.indexOf(val) == id);
If you want to remove duplicate values which contains same "id", You can use this.
const arr = [
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 2, name: "ra one" },
{ id: 3, name: "alex" },
{ id: 1, name: "devid" },
{ id: 7, name: "sam" },
];
function getUnique(arr, index) {
const unique = arr
.map(e => e[index])
// store the keys of the unique objects
.map((e, i, final) => final.indexOf(e) === i && i)
// eliminate the dead keys & store unique objects
.filter(e => arr[e]).map(e => arr[e]);
return unique;
}
console.log(getUnique(arr,'id'))
Result :
[
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 7, name: "sam" }
]
you forgot to use return statement in the filter call
const namesArr = duplicatesArray.filter(function(elem, pos) {
return duplicatesArray.indexOf(elem) == pos;
});
Since I found the code of #Infaz 's answer used somewhere and it confused me greatly, I thought I would share the refactored function.
function getUnique(array, key) {
if (typeof key !== 'function') {
const property = key;
key = function(item) { return item[property]; };
}
return Array.from(array.reduce(function(map, item) {
const k = key(item);
if (!map.has(k)) map.set(k, item);
return map;
}, new Map()).values());
}
// Example
const items = [
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 2, name: "ra one" },
{ id: 3, name: "alex" },
{ id: 1, name: "devid" },
{ id: 7, name: "sam" },
];
console.log(getUnique(items, 'id'));
/*Output:
[
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 7, name: "sam" }
]
*/
Also you can do this
{Array.from(new Set(yourArray.map((j) => j.location))).map((location) => (
<option value={`${location}`}>{location}</option>
))}

How can I get the delta from two JSON arrays?

Below are two JSON arrays. I want to get delta data (compare the two datasets and return elements that don't appear in both sets).
var data1 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" }
];
var data2 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" },
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
expected output:
var Result = [
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
I have tried this but didn't have any luck:
$.grep(data2, function (el) {
if ($.inArray(el, data1) == -1)
diff.push([el, IDl]);
});
You are close, the problem is you need to do a deep compare of your objects. inArray will only do a shallow compare. The following code will do a deep compare by checking equality of id and name. Also, it allows jQuery.grep to build the resulting array so you do not need to do this manually.
var data1 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" }
];
var data2 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" },
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
function compare(data1, data2) {
return $.grep(data2, function(el) {
return !data1.some(function(elToCompare) {
return elToCompare.id === el.id && elToCompare.name === el.name;
});
});
}
$("#output").text(JSON.stringify(compare(data1, data2)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div id="output"></div>

Categories