1

I am trying to remove duplicate entry's from this json but it is only returning one object I am not understanding where I am going wrong.

The code is as follows.

// exemplary array of objects (id 'NewLive' occurs twice)
var arr = [
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}},
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}}
],
    obj = {}, new_arr = [];

// in the end the last unique object will be considered
arr.forEach(function(v){
    obj[v['id']] = v;
   console.log(JSON.stringify(new_arr));
});
new_arr = Object.keys(obj).map(function(id) { return obj[id]; });

console.log(JSON.stringify(new_arr));

I am attaching codepen also with this.

https://codepen.io/anon/pen/oQXJWK

10
  • Are you just trying to return the same object without duplicates? Commented Nov 9, 2018 at 5:26
  • @Jacques Yes I am Commented Nov 9, 2018 at 5:27
  • Possible duplicate of Get all unique values in a JavaScript array (remove duplicates) Commented Nov 9, 2018 at 5:28
  • obj[v['id']] = v; should be obj[v['jobcodeid']] = v;. Since there is no id, you get undefined for all objects and hence you are basically replacing all values by next. Hence you get only 1 Commented Nov 9, 2018 at 5:30
  • for (const job of arr) { if (!obj[job.jobcodeid.S]) { obj[job.jobcodeid.S] = true; new_arr.push(job); } } Commented Nov 9, 2018 at 5:30

5 Answers 5

4

The reason why your code is returning a single element is because you are using v['id'] but there is no id property on the objects, therefore throughout your loop you are setting obj[undefined] over and over.

In your jsfiddle code though this looks correct and the code seems to be working as intended.

In case someone got to this question to find out how to remove duplicates from an array in javascript, here are a few options:

The classic way: good old for loop

This is essentially the solution you used, iterate over the array, check if the key has been added to the result array, and if it's not there, add the element to the result.

Example:

const result = [];
const knownIDs = new Set();
for (const item of input) {
  if (!knownIDs.has(item.jobcodeid.S)) {
    result.push(item);
    knownIDs.add(item.jobcodeid.S);
  }
}

To Map and back

To filter duplicates you can convert the elements to a Map of key -> value, and then convert back into an array. This works because keys are unique in a Map, and duplicates will be automatically eliminated. The main advantage of this method is that due to the simplicity of the code it will have fewer bugs.

console.log(
  Array.from(
    new Map(
      input.map(i => [i.jobcodeid.S, i])
    ).values()
  )
)

filter and Set

Another option is to use a Set to record known ids and filter to remove items with known ids. The advantage of this method is that it might be easier to read since the intention is explicit. Also this is more performant than converting to Map and back.

const knownKeys = new Set();
console.log(
  input.filter(i => {
    if (!knownKeys.has(i.jobcodeid.S)) {
      knownKeys.add(i.jobcodeid.S);
      return true;
   }
  })
);

See them in action:

const input = [{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}},{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}}];

// Classic for loop
const result = [];
const knownIDs = new Set();
for (const item of input) {
  if (!knownIDs.has(item.jobcodeid.S)) {
    result.push(item);
    knownIDs.add(item.jobcodeid.S);
  }
}

console.log(result.map(r => r.jobcodeid.S));

// To Map and back
console.log(
  Array.from(
    new Map(
      input.map(i => [i.jobcodeid.S, i])
    ).values()
  )
)

// filter and set
const knownKeys = new Set();
console.log(
  input.filter(i => {
    if (!knownKeys.has(i.jobcodeid.S)) {
      knownKeys.add(i.jobcodeid.S);
      return true;
   }
  })
);

For the record, I ran benchmarks on the accepted solution, mine and the performance improvements from Jacques' answer

accepted solution x 1,892,585 ops/sec ±3.48% (89 runs sampled)
Map and back x 495,116 ops/sec ±2.27% (90 runs sampled)
Set and filter x 1,600,833 ops/sec ±1.98% (90 runs sampled)
Jacques x 2,110,510 ops/sec ±0.98% (92 runs sampled)
Fastest is Jacques

As you can see, Jacques' solution is indeed twice as fast so if you are aiming to filter huge arrays or if performance is key, you should definitely choose that!

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

Comments

1

Fist of all, you have to use obj[v['jobcodeid']] = v; instead of obj[v['id']] = v;.

but as v[jobcodeid] is an object, js will convert it to a string i.e. [object Object] and you will only one element in final array.

// exemplary array of objects (id 'NewLive' occurs twice)
var arr=[{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}},{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}}], obj = {}, new_arr = [];

// in the end the last unique object will be considered
arr.forEach(function(v){
    obj[v['jobcodeid']] = v;
});
new_arr = Object.keys(obj).map(function(id) { return obj[id]; });

console.log(JSON.stringify(new_arr));

You should use v.jobcodeid.S as keys of object.

// exemplary array of objects (id 'NewLive' occurs twice)
var arr=[{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}},{"jobcodeid":{"S":"Etc_new"}},{"jobcodeid":{"S":"NewLive"}},{"jobcodeid":{"S":"NewLiveVid"}},{"jobcodeid":{"S":"New_Live"}},{"jobcodeid":{"S":"New_Live_Vid"}},{"jobcodeid":{"S":"Newest"}},{"jobcodeid":{"S":"NewestLive"}},{"jobcodeid":{"S":"NewestLiveVid"}},{"jobcodeid":{"S":"Very_New_Vid"}}], obj = {}, new_arr = [];

// in the end the last unique object will be considered
arr.forEach(function(v){
    obj[v.jobcodeid.S] = v;
});
new_arr = Object.keys(obj).map(function(id) { return obj[id]; });

console.log(JSON.stringify(new_arr));

3 Comments

I missed that in my comment. +1
Have you tested the code? Can u update the same on codepen?
You can get new_arr with just Object.values: new_arr = Object.values(obj).
1

Posting an answer to show another way to do it with greater efficiency.

var arr = [
  {"jobcodeid":{"S":"Etc_new"}
  },
  {"jobcodeid":{"S":"NewLive"}
  },
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}},
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}}
],
    obj = {}, new_arr = [];

// in the end the last unique object will be considered
for (const job of arr) {
	if (!obj[job.jobcodeid.S]) {
		obj[job.jobcodeid.S] = true;
		new_arr.push(job);
    }
}

console.log(JSON.stringify(new_arr));

This answer is always runs N iterations. When you loop through the keys after setting the unique values, it can run up to 2N iterations. (Changed from talking about Big O/Complexity to be more clear)

3 Comments

O(2n) is exactly the same as O(n) -- en.wikipedia.org/wiki/Big_O_notation
You are correct, I shouldn't use big o to explain this as it is technically used to explain how complexity grows as quantity increases. My point is that the one solution can take twice as long to complete as the other.
Even though looping twice doesn't necessarily mean slower, you are running fewer operations total, so you are right, this code would perform faster. I ran some quick benchmarks that confirm that this solution works roughly 2x faster than the next best :)
1

All you need is to use Set!

const arr = [
    { jobcodeid: { S: "Etc_new" } },
    { jobcodeid: { S: "NewLive" } },
    { jobcodeid: { S: "NewLiveVid" } },
    { jobcodeid: { S: "New_Live" } },
    { jobcodeid: { S: "New_Live_Vid" } },
    { jobcodeid: { S: "Newest" } },
    { jobcodeid: { S: "NewestLive" } },
    { jobcodeid: { S: "NewestLiveVid" } },
    { jobcodeid: { S: "Very_New_Vid" } },
    { jobcodeid: { S: "Etc_new" } },
    { jobcodeid: { S: "NewLive" } },
    { jobcodeid: { S: "NewLiveVid" } },
    { jobcodeid: { S: "New_Live" } },
    { jobcodeid: { S: "New_Live_Vid" } },
    { jobcodeid: { S: "Newest" } },
    { jobcodeid: { S: "NewestLive" } },
    { jobcodeid: { S: "NewestLiveVid" } },
    { jobcodeid: { S: "Very_New_Vid" } }
];

const uniqueItems = [...new Set(arr.map(i => i.jobcodeid.S))]

Comments

0

Try this also.. another way to solve this problem

var arr = [
  {"jobcodeid":{"S":"Etc_new"}
  },
  {"jobcodeid":{"S":"NewLive"}
  },
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}},
{"jobcodeid":{"S":"Etc_new"}},
{"jobcodeid":{"S":"NewLive"}},
{"jobcodeid":{"S":"NewLiveVid"}},
{"jobcodeid":{"S":"New_Live"}},
{"jobcodeid":{"S":"New_Live_Vid"}},
{"jobcodeid":{"S":"Newest"}},
{"jobcodeid":{"S":"NewestLive"}},
{"jobcodeid":{"S":"NewestLiveVid"}},
{"jobcodeid":{"S":"Very_New_Vid"}}
],
    obj = {}, new_arr = [];


arr.forEach(function(v){
    obj[v['id']] = v;

    for(var i=0;i< new_arr.length;i++){
      if(new_arr[i].jobcodeid.S == v.jobcodeid.S)       {
         return;
      }
    } 
      new_arr.push(v);     
});

console.log(new_arr);

1 Comment

While this would work, please consider code complexity here. You have a loop within a loop, which is very inefficient.

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.