Remove duplicated objects in JavaScript Array not working - javascript

First of, I am aware that there are LOTS of answers on SO on this, but I am having some issues with them, that is why I post another question on this topic.
So here is my Array of Objects:
0: {id: 'lAYOUT', label: 'lAYOUT', items: 'val1'}
1: {id: 'tecst', label: 'tecst', items: 'val1'}
2: {id: 'tecst', label: 'tecst', items: 'val1'}
I am trying to filter out that there would be only 2 values, since there are 2 objects in array that are the same. I would like to make unique objects by items and label.
This is how I am trying to do it with lodash:
const filteredArray = uniq(nestedItems, (item, key, a) => item.items && item.label)
But it keeps returning me all 3 elements still.
I also tried it like this:
const filteredArray = [...new Set(nestedItems)]

Using Filter get the particular object value, index and array.
Using FindIndex get the particular array object. and compare filter object and findindex object, if it return false then push in new array! and make new unique array !
Try this code !
let arr = [{ id: 'lAYOUT', label: 'lAYOUT', items: 'val1' },
{ id: 'tecst', label: 'tecst', items: 'val1' },
{ id: 'tecst', label: 'tecst', items: 'val1' }];
let newArr = arr.filter((value, index, self) =>
index === self.findIndex((t) => (
t.label === value.label && t.items === value.items
))
);
console.log(newArr, 'newArr');

You can use hash grouping to filter by several keys:
const data = [{ id: 'lAYOUT', label: 'lAYOUT', items: 'val1' }, { id: 'tecst', label: 'tecst', items: 'val1' }, { id: 'tecst', label: 'tecst', items: 'val1' }];
const unique = Object.values(data.reduce((acc, obj) => {
const hash = `${obj.id}-${obj.label}`;
acc[hash] = obj;
return acc;
}, {}));
console.log(unique);
.as-console-wrapper{min-height: 100%!important; top: 0}
Same result with lodash
const data = [{ id: 'lAYOUT', label: 'lAYOUT', items: 'val1' }, { id: 'tecst', label: 'tecst', items: 'val1' }, { id: 'tecst', label: 'tecst', items: 'val1' }];
const result = _.uniqWith(data, (o1, o2) => `${o1.id}-${o1.label}` === `${o2.id}-${o2.label}`);
console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js" integrity="sha512-2iwCHjuj+PmdCyvb88rMOch0UcKQxVHi/gsAml1fN3eg82IDaO/cdzzeXX4iF2VzIIes7pODE1/G0ts3QBwslA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

const data = [
{ id: 'id1', label: 'label1', items: 'items1' },
{ id: 'id2', label: 'label2', items: 'items2' },
{ id: 'id1', label: 'label1', items: 'items2' }
];
const unique = (...keys) => [
...new Map(data.map(item => [keys.map(key => item[key]).join(), item])).values()
];
console.log(1, unique('label'));
console.log(2, unique('label','items'));

Related

How to remap array in React [duplicate]

This question already has answers here:
How to rename properties of objects in array in javascript?
(5 answers)
Closed 4 months ago.
How to do a remapo for new objects like:
...
const inputArr = [
{id: '1', name: "test1", routeName: "somethig/something"},
{id: '2', name: "something2", routeName: "foo/bar"},
{id: '3', name: "someanothrelement", routeName: "test/test"}
]
//to =>
const resultStructureArr = [
{ id: '1', value: 'somethig/something', label: 'test1' },
{ id: '2', value: 'foo/bar', label: 'something2' },
{ id: '3', value: 'test/test', label: 'someanothrelement' },
];
...
Here is the jsfiddle
Just using map() can do it
const inputArr = [
{id: '1', name: "test1", routeName: "somethig/something"},
{id: '2', name: "something2", routeName: "foo/bar"},
{id: '3', name: "someanothrelement", routeName: "test/test"}
]
let result = inputArr.map(a => ({'id':a.id,'label':a.name,'value':a.routeName}))
console.log(result)
We can use traditional for loop for this. Where we may loop to the length of list and for each iteration we may add new object into result array using Array.prototype.push method. Secondly we are doing the same thing with foreach loop. Third I'm using Array.prototype.map method, Which creates a new result for each iteration, in our case we are returning our new object. Lastly we are using Array.prototype.reduce method, with this method we can initialize a starting value which in my case I'm using empty array, then for each iteration I'm pushing a new object in that array and returning it.
const inputArr = [
{ id: "1", name: "test1", routeName: "somethig/something" },
{ id: "2", name: "something2", routeName: "foo/bar" },
{ id: "3", name: "someanothrelement", routeName: "test/test" },
];
// Using for loop
let result = [];
for (let i = 0; i < inputArr.length; i++) {
result.push({
id: inputArr[i].id,
value: inputArr[i].routeName,
label: inputArr[i].name,
});
}
console.log(result);
result = [];
// using foreach loop
inputArr.forEach((item) => {
result.push({ id: item.id, label: item.name, value: item.routeName });
});
console.log(result);
result = [];
// using map
result = inputArr.map((item) => ({
id: item.id,
label: item.name,
value: item.routeName,
}));
console.log(result);
result = [];
// using reduce
result = inputArr.reduce((acc, curr) => {
acc.push({ id: curr.id, label: curr.name, value: curr.routeName });
return acc;
}, []);
console.log(result);

Programmatically find specific node and add property to deep nested object [duplicate]

This question already has answers here:
Dynamically set property of nested object
(28 answers)
Find by key deep in a nested array
(21 answers)
Closed last year.
Given an array like this, where the maximum depth can be 3 levels and where we don't know at what level the researched item could be:
const data = {
id: '1',
children: [
{
id: '2',
name: 'nameTest',
children: [
{
id: '3'
name: 'deepLevel'
}
]
}
}
how can I add a property to the third level knowing only the value 'deepLevel' ?
we are allowed to use lodash and strongly encouraged to use ES6.
the final dataStructure should be
Given an array like this, where the maximum depth can be of 3 levels:
const data = {
id: '1',
children: [
{
id: '2',
name: 'nameTest',
children: [
{
id: '3'
name: 'deepLevel'
addedProperty: true,
}
]
}
}
An approach was to separate the tasks of finding a nested item by a custom(izable) entry (key-value pair) and assigning additional custom data to the found item.
Thus one e.g. could implement two methods recursivelyFindItemByEntry which is based on self recursion and a simple assignToObjectWithFirstMatchingNestedEntry which assigns provided data to the result of the former function invocation ...
function recursivelyFindItemByEntry(obj, [key, value]) {
let item;
if (!!obj && (typeof obj === 'object')) {
if (
obj.hasOwnProperty(key) &&
(obj[key] === value)
) {
item = obj;
} else if (
obj.hasOwnProperty('children') &&
Array.isArray(obj.children)
) {
obj.children.some(child => {
item = recursivelyFindItemByEntry(child, [key, value]);
return !!item;
});
}
}
return item;
}
function assignToObjectWithFirstMatchingNestedEntry(obj, [key, value], data) {
Object.assign(
recursivelyFindItemByEntry(obj, [key, value]) ?? {},
data ?? {}
);
return obj;
}
const data = {
id: '1',
children: [{
id: '2',
name: 'nameTest',
children: [{
id: '3',
name: 'deepLevel',
}, {
id: '4',
name: 'deepLevel',
}],
}, {
id: '5',
name: 'nameTest',
children: [{
id: '6',
name: 'deepLevel',
}, {
id: '7',
name: 'deepLevelTarget',
// addedProperty: true,
}, {
id: '8',
name: 'deepLevel',
}],
}, {
id: '9',
name: 'nameTest'
}, {
id: '10',
name: 'nameTestTarget'
}, {
id: '11',
name: 'nameTest'
}],
};
console.log(
"recursivelyFindItemByEntry(data, ['name', 'deepLevelTarget']) ...",
recursivelyFindItemByEntry(data, ['name', 'deepLevelTarget'])
);
console.log(
"recursivelyFindItemByEntry(data, ['id', '10']) ...",
recursivelyFindItemByEntry(data, ['id', '10'])
);
console.log('\n');
console.log(
"recursivelyFindItemByEntry(data, ['id', 'foo']) ...",
recursivelyFindItemByEntry(data, ['id', 'foo'])
);
console.log(
"recursivelyFindItemByEntry(data, ['id', '1']) ...",
recursivelyFindItemByEntry(data, ['id', '1'])
);
console.log('\n');
console.log(
"assignToObjectWithFirstMatchingNestedEntry(data, ['name', 'deepLevelTarget']), { addedProperty: true } ...",
assignToObjectWithFirstMatchingNestedEntry(data, ['name', 'deepLevelTarget'], { addedProperty: true })
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Remove equal objects from array

I have the following problem in JavaScript: I want to check an array for duplicates. My example array only has 6 objects here.
var list = [
{id: "1", label: "Nils"},
{id: "2", label: "Max"},
{id: "3", label: "Thomas"},
{id: "4", label: "Tom"},
{id: "5", label: "Joschua"},
{id: "5", label: "Joschua"}];
In the later project it can also be more than 500, which I import via a CSV file.
And now I want to remove duplicates. At first I tried the set method:
var newList = [... new Set(list)];
console.log(newList);
The result is false. The array has the same objects.
Then I tried a simple if query:
if(list[4]==list[5]){
console.log("equal") }else{
console.log("unequal")}
The result is unequal. I don't understand why.
The array should look like this:
[{ id: '1', label: 'Nils' },
{ id: '2', label: 'Max' },
{ id: '3', label: 'Thomas' },
{ id: '4', label: 'Tom' },
{ id: '5', label: 'Joschua' }]
If the ids are meant to be unique, you can use Array#filter with a Set based on the id.
var list = [
{id: "1", label: "Nils"},
{id: "2", label: "Max"},
{id: "3", label: "Thomas"},
{id: "4", label: "Tom"},
{id: "5", label: "Joschua"},
{id: "5", label: "Joschua"}];
const set = new Set,
res = list.filter(x => !set.has(x.id) && set.add(x.id));
console.log(res);
Set cannot compare object altogether, it only works with primitives types like number or string.
You can use a Map that is based on a key/value paradigm though, like :
const list = [
{id: '1',label: 'Nils'},
{id: '2', label: 'Max'},
{id: '3', label: 'Thomas'},
{id: '4', label: 'Tom'},
{id: '5', label: 'Joschua'},
{id: '5', label: 'Joschua'},
];
const map = new Map();
// Push the values into the map
list.forEach(({
id,
label,
}) => map.set(id, label));
// Transform the map into an array of object
const uniqueList = Array.from(map, ([id, label]) => ({
id,
label,
}));
console.log(uniqueList);
Or using an Array.reduce combined with an Array.map
const list = [
{id: '1', label: 'Nils'},
{id: '2', label: 'Max'},
{id: '3', label: 'Thomas'},
{id: '4', label: 'Tom'},
{id: '5', label: 'Joschua'},
{id: '5', label: 'Joschua'},
];
const uniqueList = Object.entries(list.reduce((tmp, {
id,
label,
}) => {
tmp[id] = label;
return tmp;
}, {})).map(([
id,
label,
]) => ({
id,
label,
}));
console.log(uniqueList);
Then I tried a simple if query:
if(list[4]==list[5]){ console.log("equal") }else{
console.log("unequal")} The result is unequal. I don't understand why.
== uses Abstract Equality Comparison Algorithm.
At first this algorithm checks if the types are the same
-> which they are.
Then the algorithm proceeds with the first step, and goes down to check if they both referencing the same object
-> they don't referencing the same object
That is the reason why it prints out false
Each usage of {} creates a new object, so this check fails and the result is false.
let a = {}
let b = {}
console.log(a==b);
Or like in your example
let a = {id: "5", label: "Joschua"};
let b = {id: "5", label: "Joschua"};
console.log(a==b);
Solution
To check if two objects are equal you can do the following
let a = {
id: 5,
name: "Max"
}
let b = {
id: 5,
name: "Max"
}
function areTheObjectsEqual(obj1, obj2) {
let keysObj1 = Object.keys(obj1);
let keysObj2 = Object.keys(obj2);
// first check if they have the same amount of keys, if not return false
if (keysObj1.length !== keysObj2.length) {
return false;
}
let valuesObj1 = Object.values(obj1);
let valuesObj2 = Object.values(obj2);
// then compare if they have the same values
for(let i = 0; i < valuesObj1.length; i++){
if(valuesObj1[i] !== valuesObj2[i]){
return false;
}
}
return true;
}
console.log(areTheObjectsEqual(a,b));

How to compare two array object in javascript if it match want to update object in array1?

I have two array objects and want to compare them in such a way that when the symbol value in array1 matches the keyNumber in array2 then set the corresponding checked value in array1 to true.
I am using .map with both arrays but not able to get the desired result.
These are my two arrays:-
const array1 = [{
symbol: '1',
checked: false
},
{
symbol: '2',
alias: 'abc',
checked: false
},
{
symbol: '3',
alias: 'def',
checked: false
}];
const array2= [{
keyNumber: '1',
type: 'number',
},
{
keyNumber: '2',
type: 'number'
}];
Following is the code to get updated array:
const array3 = array1.map(item => {
return array2
.map(key =>
key.keyNumber === item.symbol
? { ...item, checked: true, type: key.type }
: item
)
.reduce((obj, data) => data, {});
});
console.log(array3);
I am getting only last key matched result instead of all.
array3 = [{
symbol: '1',
checked: false
},
{
symbol: '2',
alias: 'abc',
checked: true,
type: 'number'
},
{
symbol: '3',
alias: 'def',
checked: false
}];
Expected output:
array3 = [{
symbol: '1',
checked: true,
type:'number'
},
{
symbol: '2',
alias: 'abc',
checked: true,
type: 'number'
},
{
symbol: '3',
alias: 'def',
checked: false
}];
Here you can check my solution.
const newArray = array1.map(obj1 => {
const match = array2.find(obj2 => obj1.symbol === obj2.keyNumber);
if(match) {
obj1 = {...obj1, checked: true, type: match.type}
}
return obj1;
})
Here is the full working code.
const array1 = [{
symbol: '1',
checked: false
},
{
symbol: '2',
alias: 'abc',
checked: false
},
{
symbol: '3',
alias: 'def',
checked: false
}];
const array2= [{
keyNumber: '1',
type: 'number',
},
{
keyNumber: '2',
type: 'number'
}];
const newArray = array1.map(obj1 => {
const match = array2.find(obj2 => obj1.symbol === obj2.keyNumber);
if(match) {
obj1 = {...obj1, checked: true, type: match.type}
}
return obj1;
})
console.log(newArray)
You can also do this with reduce by concatenating the second array in the last. In this case you wont have to find the first array for every loop.
var array1 = [{ symbol: '1', checked: false }, { symbol: '2', alias: 'abc', checked: false }, { symbol: '3', alias: 'def', checked: false }];
var array2= [{ keyNumber: '1', type: 'number', }, { keyNumber: '2', type: 'number' }];
array1 = [...array1, ...array2];
var result = Object.values(array1.reduce((acc, {symbol, keyNumber, ...rest})=>{
data1 = symbol || keyNumber;
acc[data1] = acc[data1] || {};
if(symbol) acc[data1] = {symbol, ...rest};
if(keyNumber) { acc[data1].type = rest.type, acc[data1].checked=true };
return acc;
},{}));
console.log(result);

sorting outer array of object by key value in the internal array object

I have array of object and it has in another array of obj, how to sort this array depend on equal actionId key in the inside array?
so this my original array:
const arrayOfItems = {
items: [
{
item: '1',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
},
{
item: '2',
anotherArray: []
},
{
item: '3',
anotherArray: []
},
{
item: '4',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
},
{
item: '5',
anotherArray: []
},
{
item: '6',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
}
]
};
the result should be all items that has the same actionId under each other
sortedArray = {
items: [
{
item: '1',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
},
{
item: '4',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
},
{
item: '6',
anotherArray: [{ actionId: '1234-dh4t-tr21-6sw8' }]
},
...
]
};
This is what I tried:
const sortingArray = arrayOfItems.items.sort((a, b) => {
return a.anotherArray > 0 && a.anotherArray[0].actionId.localeCompare(b.anotherArray[0].actionId);
})
Something like this does the trick. This sorts based upon ActionId, then item. Items without an actionId will be moved to the end of the array.
const arrayOfItems = {items: [{item: '1', anotherArray: [{actionId: '1234-dh4t-tr21-6sw8'}]}, {item: '2', anotherArray: []}, {item: '3', anotherArray: []}, {item: '4', anotherArray: [{actionId: '1234-dh4t-tr21-6sw8'}]}, {item: '5', anotherArray: []}, {item: '6', anotherArray: [{actionId: '1234-dh4t-tr21-6sw8'}]}]};
arrayOfItems.items.sort((a, b) => {
const lenA = a.anotherArray.length,
lenB = b.anotherArray.length;
// order based on item if both a and b don't have an actionId
if (!lenA && !lenB) return a.item - b.item;
// move the element without actionId towards the end if a or b doesn't have an actionId
if (!lenA || !lenB) return lenB - lenA;
const actionIdA = a.anotherArray[0].actionId,
actionIdB = b.anotherArray[0].actionId;
// order based on item if both a and b have the same actionId
if (actionIdA === actionIdA) return a.item - b.item;
// order based on actionId
return actionIdA.localeCompare(actionIdB);
});
console.log(arrayOfItems.items);
If you don't care about ordering by item second, you can remove:
// order based on item if both a and b don't have an actionId
if (!lenA && !lenB) return a.item - b.item;
And:
// order based on item if both a and b have the same actionId
if (actionIdA === actionIdA) return a.item - b.item;

Categories

Resources