0

I have an array of duplicated objects in Javascript. I want to create an array of unique objects by adding the index of occurrence of the individual value.

This is my initial data:

const array= [
  {name:"A"},
  {name:"A"},
  {name:"A"},
  {name:"B"},
  {name:"B"},
  {name:"C"},
  {name:"C"},
];

This is expected end result:

const array= [
  {name:"A-0"},
  {name:"A-1"},
  {name:"A-2"},
  {name:"B-0"},
  {name:"B-1"},
  {name:"C-0"},
  {name:"C-1"},
];

I feel like this should be fairly simple, but got stuck on it for a while. Can you please advise how I'd go about this? Also if possible, I need it efficient as the array can hold up to 1000 items.


EDIT: This is my solution, but I don't feel like it's very efficient.

const array = [
  { name: "A" },
  { name: "A" },
  { name: "C" },
  { name: "B" },
  { name: "A" },
  { name: "C" },
  { name: "B" },
];

const sortedArray = _.sortBy(array, 'name');

let previousItem = {
   name: '',
   counter: 0
};
const indexedArray = sortedArray.map((item) => {
  if (item.name === previousItem.name) {
    previousItem.counter += 1;
    const name = `${item.name}-${previousItem.counter}`;
    return { name };
  } else {
    previousItem = { name: item.name, counter: 0};
    return item;
  }
});
3
  • What was the result you got? Show where you got stuck. Commented Sep 26, 2020 at 23:58
  • If they're sorted like that, it should just be a simple matter of using a counter variable, keeping track of the current letter, and then resetting the counter when you get a new letter. Commented Sep 26, 2020 at 23:59
  • posted my solution as an edit. thanks, the counter idea helped me to solve it Commented Sep 27, 2020 at 0:17

2 Answers 2

1

Currently you are sorting it first then looping over it, which may be not the most efficient solution.

I would suggest you to map over it with a helping object.

const a = [{name:"A"},{name:"A"},{name:"A"},{name:"B"},{name:"B"},{name:"C"},{name:"C"},], o = {};

const r = a.map(({ name }) => {
   typeof o[name] === 'number' ? o[name]++ : o[name] = 0;
   return { name: `${name}-${o[name]}` };
});
   
console.log(r);

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

2 Comments

I accepted your answer as the best solution as jsbench shows it as the fastest. I'm gonna break it down to understand how you used the helping object. thanks!
@mhlavacka The helping object basically stores the info how many times particular name was looped already.
1

Keep a counter, and if the current name changes, reset the counter.

This version mutates the objects. Not sure if you want a copy or not. You could potentially sort the array by object name first to ensure they are in order (if that's not already an existing precondition.)

const array = [
  { name: "A" },
  { name: "A" },
  { name: "A" },
  { name: "B" },
  { name: "B" },
  { name: "C" },
  { name: "C" },
];

let name, index;
for (let i in array) {
  index = array[i].name == name ? index + 1 : 0;
  name = array[i].name;
  array[i].name += `-${index}`;
}

console.log(array);


Another way, if you don't want to sort, and don't want to mutate any objects, is to use a map and keep track of the current index for each object.

const array = [
  // NOTE: I put the items in mixed up order.
  { name: "A" },
  { name: "C" },
  { name: "A" },
  { name: "B" },
  { name: "A" },
  { name: "C" },
  { name: "B" },
];

let index = {};
let next = name => index[name] = index[name] + 1 || 0;
let result = array.map(obj => ({ ...obj, name: obj.name + '-' + next(obj.name) }));
console.log(result);

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.