Reputation: 254
I have an array containing duplicate elemnets
let myArray=[
{role: "role-1", deviceId: ""},
{role: "role-2", deviceId: "d-2"},
{role: "role-3", deviceId: "d-3"},
{role: "role-1", deviceId: "d-1"},
{role: "role-2", deviceId: ""},
{role: "role-4", deviceId: ""}
{role: "role-5", deviceId: ""}
]
I want to remove the duplicate roles and have array which contains roles without empty("") deviceIds and if deviceId is empty keep only one role without duplicates in this way
myArray=[
{role: "role-1", deviceId: "d-1"},
{role: "role-2", deviceId: "d-2"},
{role: "role-3", deviceId: "d-3"}
{role: "role-4", deviceId: ""}
{role: "role-5", deviceId: ""}
]
I have written the function in this way
function dedupeByKey(arr, key) {
const temp = arr.map(el => el[key]);
return arr.filter((el, i) =>
temp.indexOf(el[key]) === i
);
}
console.log(dedupeByKey(myArray, 'role'));
But in the result, its not checking to give priority for deviceId with values and role with empty deviceId is getting added. How to fix this?
Upvotes: 3
Views: 2919
Reputation: 128
You could apply a filter an look ahead in the array for duplicates to decide to filter the index or keep it
const myArray= [
{role: "role-1", deviceId: ""},
{role: "role-2", deviceId: ""},
{role: "role-3", deviceId: "d-3"},
{role: "role-1", deviceId: "d-1"},
{role: "role-2", deviceId: ""},
{role: "role-4", deviceId: ""},
{role: "role-5", deviceId: ""}
]
const cleanArray = myArray.filter( (item,index,array) => {
if ( item.deviceId === "") {
// filter it out when the same role is found in the array and the index isn't the same as current item you are looking at
return !array.some((i,idx) => i.role === item.role && idx > index )
}
return true
})
// for presentation: sort the array
const sortedArray = cleanArray.sort( (curr, next) => curr.role > next.role? 1:-1);
console.log(sortedArray)
Upvotes: 1
Reputation: 2970
You can map the unique role to an object and reduce the object to an array as following code snippet
let myArray = [
{role: "role-1", deviceId: ""},
{role: "role-2", deviceId: "d-2"},
{role: "role-3", deviceId: "d-3"},
{role: "role-1", deviceId: "d-1"},
{role: "role-2", deviceId: ""},
{role: "role-4", deviceId: ""},
{role: "role-5", deviceId: ""}
];
var uniqueObj = myArray.reduce(function(acc, item) {
var deviceId = acc[item.role] && acc[item.role].deviceId || item.deviceId;
acc[item.role] = item;
acc[item.role].deviceId = deviceId;
return acc;
}, {});
var result = Object.keys(uniqueObj).reduce(function(acc2, item) {
acc2.push(uniqueObj[item]);
return acc2;
}, []);
console.log(result);
Upvotes: 1
Reputation: 10621
You can use reduce with default to object, and if you need, you can convert it to array at the end.
let myArray = [
{role: "role-1", deviceId: ""},
{role: "role-2", deviceId: "d-2"},
{role: "role-3", deviceId: "d-3"},
{role: "role-1", deviceId: "d-1"},
{role: "role-2", deviceId: ""},
{role: "role-4", deviceId: ""},
{role: "role-5", deviceId: ""}
]
const res = myArray.reduce((agg, itr) => {
if (agg[itr.role]) return agg // if deviceId already exist, skip this iteration
agg[itr.role] = itr.deviceId // if deviceId not exist, Add it
return agg
}, {})
let make_array = Object.keys(res).map(key => { return { role: key, deviceId: res[key] }})
console.log(make_array)
Upvotes: 1
Reputation: 138234
I'd group by role
, then take the first with an deviceId
:
function groupBy(array, key) {
const result = { };
for(const el of array) {
if(!result[ el[key] ]) result[ el[key] ] = [];
result[ el[key] ].push(el);
}
return result;
}
const result = [];
const grouped = groupBy(myArray, "role");
for(const group of Object.values(grouped)) {
result.push(group.find(it => it.deviceId) || group[0]);
}
Upvotes: 0