3

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?

3
  • 1
    Why role-2 have deviceId: "d-21"? Commented Nov 18, 2018 at 12:23
  • @omri_saadon My bad. I edited Commented Nov 18, 2018 at 12:25
  • 1
    Also, why you have role-3 twice in the result while at the beginning you had one? Commented Nov 18, 2018 at 12:27

4 Answers 4

1

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)

Sign up to request clarification or add additional context in comments.

Comments

1

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);

Comments

1

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)

Comments

0

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]);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.