Javascript - Remove duplicate ID from array of objects - javascript

Take the following two arrays:
const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '#item1#',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '#item2#',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '#item1#',
},
}
];
What I'm trying to do is concatenate them into a single array, and remove any duplicates based on the id property. However the caveat here is that the object that does NOT have a type of hidden must have presidence.
So I should basically be left with the contents of array1, as the duplicate item from array2 has the type value of hidden, like so:
// Result
[
{
props: {
type : 'text', // Note the type here is "text"
id : 'item1',
name : 'item1',
value : '#item1#',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '#item2#',
},
}
];
I can easily concatenate them using:
const array = array1.concat(array2);
My idea was to then use a Filter but I'm having a bit of a brain melt. Here is what I have come up with so far:
const concat = (array1, array2) => {
const array = array1.concat(array2);
const ids = [];
// Create array of ID's
for (const i in array1) {
ids.push(array1[i].props.id);
}
return array.filter((obj) => {
if (obj.props.type !== 'hidden' && ids.includes(obj.props.id)) {
return true;
}
return false;
});
};
Would using a Reduce be a better approach here?
Here is a JSFiddle of what I have so far: https://jsfiddle.net/64uprbhn/

You can
Create a Map of id => object from the first array
Go over the second array and either
add the item if not already in the map
check if the current item is not type: "hidden" and overwrite the other one
otherwise discard the item
Create a new array from the Map
const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '#item1#',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '#item2#',
},
},
{
props: {
type: 'hidden',
id: 'item3',
name: 'item3',
value: '#item3#',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '#item1#',
},
},
{
props: {
type: 'text',
id: 'item3',
name: 'item3',
value: '#item3#',
},
}
];
//1. create a map from id => object pairs
const map = new Map(array1.map(obj => [obj.props.id, obj]));
//2. go over the second array
array2.forEach(obj => {
if (!map.has(obj.props.id) //not a duplicate
|| obj.props.type !== "hidden") { //is not hidden
//insert
map.set(obj.props.id, obj);
}
});
//3. convert back into array
const merged = [...map.values()];
console.log(merged);
For the record, you can basically do the same (or pretty similar) thing using .filter but you'll have to do a O(n) lookup for each item. A Map ensures much faster lookups.

const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '#item1#',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '#item2#',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '#item1#',
},
}
];
function getUnique(arr, comp) {
const unique = arr
.map(e => e[comp])
// 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;
}
const arr = array1.concat(array2);
console.log(getUnique(arr, 'id'));

Here's what worked for me
const someItems = [{ id: 1 }, { id: 2 }, { id: 1 }]
function getUniqueItems(items) {
const uniqueIds = new Set(items.map((item) => item.id))
const itemsWithUniqueIds = [...uniqueIds].map(id => items.find(item => item.id === id)).filter(Boolean)
return itemsWithUniqueIds
}
console.log(getUniqueItems(someItems))
If you are using TypeScript, TS will complain about the .filter(Boolean). In that case just replace Boolean with (item: any | undefined): item is any => Boolean(item). Of course, you can then go ahead and also replace any with whichever type makes sense in your case.

Related

How to find the length of particular type within object using javascript?

i have object like below,
Example 1
input = {
item_type: {
id: ‘1’,
name: ‘name1’,
},
children: [
{
type_1: {
id: ‘12’,
},
type: 'item1-type',
},
{
children: [
{
id: '1',
type: 'item2',
},
{
id: '2',
type:'item2',
},
{
id:'3',
type: 'item2',
},
]
type: 'item2-type',
},
{
children: [
{
id: '4',
type: 'item2',
},
{
id: '5',
type:'item2',
},
{
id:'6',
type: 'item2',
},
]
type: 'item2-type',
},
]
}
now i want to find the count of "item2" type within children array within children array again.
note that the outer children array can be empty array and the children array within children array may not be present. so the input can be of types like below
input = {
item_type: {
id: ‘1’,
name: ‘name1’,
},
children: [] //empty children array
}
input = {
item_type: {
id: ‘1’,
name: ‘name1’,
},
children:
[ //no children array within
{
type_1: {
id: ‘12’,
},
type: “item1-type”,
},
]
}
how can i find the count of type: "item2" within children array considering example1 input.
so the expected count is 6.
could someone help me with this. thanks. new to programming.
const findAllChildrenOfType = (obj, type) => {
let count = 0;
if (obj.type === type) count++;
if (obj.children) {
obj.children.forEach(child => {
const childCount = findAllChildrenOfType(child, type);
count += childCount;
})
}
return count;
}
console.log(findAllChildrenOfType(input, "item2"))

How to update a value in nested array based on the given index and return original array in javascript?

I have an index '3_1_0' and the following array:-
var fields = [
{
name: 'a'
},
{
name: 'b'
},
{
name: 'c'
},
{
name: 'd',
fields: [
{
name: 'd1'
},
{
name: 'd2',
fields: [
{
name: 'd2.1'
}
]
}
]
}
]
I need to extract the element from the above fields array based on the index. so 3_1_0 will extract following
{
name: 'd2.1'
}
Update the value from d2.1 to some other value like 'new_d2.1' and attach the updated value at the same index in original fields array and return the updated fields array. How this can be done?
You can use Array.reduce to get the desired result. We start by splitting the index into an array, then reducing to get the result.
We'll use some Optional Chaining to ensure we'll return undefined if no value is found (say our index was '7_10_20').
Once we've found our object, we can set the required property.
const fields = [ { name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
const index = '3_1_0'
function setValue(fields, index, property, value) {
const obj = index.split('_').reduce((acc, key) => {
return acc?.[key] || acc?.fields?.[key];
}, fields);
// Only update if we actually find anything
if (obj) {
obj[property] = value
}
}
setValue(fields, '3_1_0', 'name', 'new_d2.1');
console.log("Fields:", fields);
const data = [{ name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
let givenIdxs = "3_1_0";
let indexes = givenIdxs.split("_");
let result = data[indexes[0]];
for(let idx = 1; idx < indexes.length; idx++){
result = result.fields[indexes[idx]];
}
console.log(result);

How to find an object from recursive array of objects that is matching with the id using javascript and react?

i have data like below,
const items = [
{
id: '1',
name: 'item1',
subItems: [{
id: '1',
name: 'subitem-1',
}],
},
{
id: '2',
name: 'item2',
subItems: [{
id: '2',
name: 'subitem-1',
}],
}
]
Now i want to find the subItem that matches with id 2. so from above data expected output is
{
id: '2',
name: 'subitem-1',
}
i have tried something like below,
const subItem = Items.find(
(item: any) =>
item.subItems &&
item.subItems.some(
(subItem: any) => subItem.id === '2'
)
);
but this will return the item that contains the subItem with id = '2'.
how can i fix the above code such that i get the SubItem instead of item?
could someone help me with this. thanks.
You could use the following, which will search and return only the inner object that is found.
const items = [
{
id: "1",
name: "item1",
subItems: [
{
id: "1",
name: "subitem-1"
}
]
},
{
id: "2",
name: "item2",
subItems: [
{
id: "2",
name: "subitem-1"
}
]
}
];
function innerFind(array, key, value) {
for (const obj of array) {
const item = obj.subItems.find((el) => el[key] === value);
if (item != null) return item;
}
}
console.log(innerFind(items, 'id', '2'));
You pass in your items array, the key you want to search for ('id'), and then the value you want to search for ('2'). This function will return the first sub item it finds that matches.

Filtering array of objects if specific key contains search term

I am trying to filter through an object with multiple key/value pairs by a specific key. It appears that the code I've written is searching the entire object regardless of the key...
If key name contains the search term, return the search term.
Array of Objects:
export const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
]
Search:
const searchResults = someArrayOfObjects.filter((o) =>
Object.keys(o).some((k) => o[k].toString().toLowerCase().includes(searchTerm.toLowerCase()))
);
So if I search "Something", I only want it to loop through name to search for that term...
You don't need the Object.keys loop.
const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
];
let key = 'name';
let searchTerm = 'th';
const res = someArrayOfObjects.filter(o =>
o[key].toLowerCase().includes(searchTerm.toLowerCase()));
console.log(res);
similar to iota's, you don't need to create the extra array with Object.keys.
just loop/check every item inside the original array with the 'name' key.
you can also try to make it more reusable like below.
const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
];
const search = function (anyArray, searchTerm) {
return anyArray.filter((obj) => {
if (obj.name === searchTerm) {
return obj.name;
}
return false;
});
};
const case1 = search(someArrayOfObjects, 'Something');
console.log(case1);

Return duplicate objects and its position in javascript

I have a big set of objects in javascript array. I Need to find all duplicate object having same name.
e.g.
values = [
{ name: 'Name1', index:0 },
{ name: 'Name2', index:1 },
{ name: 'Name1', index:2 },
{ name: 'Name2', index:3 },
{ name: 'Name1', index:4 },
]
What I expect is a array having two objects
values = [
{ name: 'Name1', index:2 },
{ name: 'Name2', index:3 },
{ name: 'Name1', index:4 }
]
because these are the duplicates.
New additions to ES6 are really interesting here, such as the Set class. This code does not modify your initial object, but it's simple to adapt.
function unique(values) {
const knownNames = new Set();
const result = [];
for (const value of values) {
if (!knownNames.has(value.name)) {
knownNames.add(value.name);
result.push(value);
}
}
return result;
}
This probably isn't the most efficient way and you should probably use the Set if you don't need to worry about IE9
values = [
{ name: 'Name1', index:0 },
{ name: 'Name2', index:1 },
{ name: 'Name1', index:2 },
{ name: 'Name2', index:3 },
{ name: 'Name1', index:4 },
]
// check an array for an object with a matching name property
// `some` will return early so you don't need to process the whole array
// if a match is found
const contains = (name, arr) => arr.some(item => item.name === name)
// reduce the array to keep the value contained
const output = values.reduce((acc, value) => {
if (!contains(value.name, acc)) {
return acc.concat(value)
}
return acc
}, [])
console.log('first unique', output)

Categories

Resources