最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Sort array by unique id, by keeping last in Javascript - Stack Overflow

programmeradmin6浏览0评论

I'm trying to make unique id list from an array that has multiple same id's. But I want it to keep the last one, not the first one. The code I have here keeps first unique object. Is there an Array.findLastIndex() I can use here. I searched but couldn't find a similar question.

[{id:2,name:'first'}, {id:2,name:'second'}, {id:3}]
    .filter((v, i, a) => a.findIndex((t) => (t.id === v.id)) === i)

That code returns :

[{id: 2, name: "first"}, {id: 3}]

But I want:

[{id: 2, name: "second"}, {id: 3}]

I have wrote the next one which gives me the result, but ideally I do not want to copy and reverse my array twice, it will be quite inefficient for long arrays.

[{id:2,name:'first'}, {id:2,name:'second'}, {id:3}]
  .slice().reverse()
  .filter((v, i, a) => a.findIndex((t) => (t.id === v.id)) === i)
  .reverse()

I'm trying to make unique id list from an array that has multiple same id's. But I want it to keep the last one, not the first one. The code I have here keeps first unique object. Is there an Array.findLastIndex() I can use here. I searched but couldn't find a similar question.

[{id:2,name:'first'}, {id:2,name:'second'}, {id:3}]
    .filter((v, i, a) => a.findIndex((t) => (t.id === v.id)) === i)

That code returns :

[{id: 2, name: "first"}, {id: 3}]

But I want:

[{id: 2, name: "second"}, {id: 3}]

I have wrote the next one which gives me the result, but ideally I do not want to copy and reverse my array twice, it will be quite inefficient for long arrays.

[{id:2,name:'first'}, {id:2,name:'second'}, {id:3}]
  .slice().reverse()
  .filter((v, i, a) => a.findIndex((t) => (t.id === v.id)) === i)
  .reverse()
Share Improve this question edited Jun 27, 2019 at 20:45 Shidersz 17.2k2 gold badges27 silver badges51 bronze badges asked Jun 27, 2019 at 18:11 chickenschickens 22.4k7 gold badges61 silver badges57 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 6

You can store them in a Map id => object, and pull the values back out:

arr = [{id:2,name:'first'},{id:2,name:'second'},{id:3}]

result = [...new Map(arr.map(x => [x.id, x])).values()]

console.log(result)

Since the Map constructor overwrites existing values, you automagically get the last one.

As noted in the ments, after this, the result elements will be ordered by the first occurrence, not by the last:

arr = [
   {id:3,name:'first 3'},
   {id:2,name:'first 2'},
   {id:2,name:'second 2'},
   {id:3,name:'second 3'}]

result = [...new Map(arr.map(x => [x.id, x])).values()]

console.log(result)

If you additionally want to sort by id, as your title suggests, then add

.sort((a, b) => a.id - b.id)

to the above.

One solution is to use Array.reduce() to generate an object using the id property as the keys while overwriting previous values. Then you can use Object.values() on the generated object:

let arr = [
  {id:2, name:'first'},
  {id:2, name:'second'},
  {id:3}
];

let res = Object.values(arr.reduce((acc, obj) => (acc[obj.id] = obj, acc), {}));
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

You could reverse the array and take the first found uniqe value. After filtering reverse the result set.

var array = [{ id: 2, name: 'first' }, { id: 2, name: 'second' }, { id: 3 }],
    unique = array
        .reverse()
        .filter((s => ({ id }) => !s.has(id) && s.add(id))(new Set))
        .reverse();

console.log(unique);

A classic approach.

var array = [{ id: 2, name: 'first' }, { id: 2, name: 'second' }, { id: 3 }],
    seen = Object.create(null),
    unique = array.reduceRight((r, o) => {
        if (!seen[o.id]) {
            r.unshift(o);
            seen[o.id] = true;
        }
        return r;
    }, []);

console.log(unique);

I like Shidersz answer the most, but here's another possibility:

    let arr = [
      {id:2, name:'first'},
      {id:2, name:'second'},
      {id:3}
    ];

    let res = arr.filter((v, i) => {
      for (let j = i + 1; j < arr.length; j++) {
        if (v.id === arr[j].id) return false
      }
      return true;
    })
    console.log(res);

My guess is that it uses less memory (doesn't have to create an intermediate object) but it probably runs slower due to not using constant time to look for duplicates. Not by much though, since the lookup is quite scope between current value and next first duplicate.

发布评论

评论列表(0)

  1. 暂无评论