如何在JavaScript中仅使用一个变量声明对数组进行正确排序并删除重复项?

如何在JavaScript中仅使用一个变量声明对数组进行正确排序并删除重复项?,javascript,arrays,ecmascript-6,Javascript,Arrays,Ecmascript 6,所以我有一个工作代码,它将数组从最高id排序到最低id,然后删除重复项 假设我们有一系列的活动: [ { id: 1, contact_id: 2, some_field: true }, { id: 2, contact_id: 3, some_field: true }, { id: 3, contact_id: 4,

所以我有一个工作代码,它将数组从最高id排序到最低id,然后删除重复项

假设我们有一系列的活动:

[
    {
        id: 1,
        contact_id: 2,
        some_field: true
    },
    {
        id: 2,
        contact_id: 3,
        some_field: true
    },
    {
        id: 3,
        contact_id: 4,
        some_field: false
    },
    {
        id: 4,
        contact_id: 3,
        some_field: true
    },
    {
        id: 5,
        contact_id: 4,
        some_field: false
    }
]
因此,删除重复的
联系人id
并从最高id到最低id排列的输出必须为:

[
    {
        id: 5,
        contact_id: 4,
        some_field: false
    },
    {
        id: 4,
        contact_id: 3,
        some_field: true
    },
    {
        id: 1,
        contact_id: 2,
        some_field: true
    }
]
我的代码如下所示:

// Sort by latest to oldest activity
arr = arr.sort((a, b) => b.id > a.id);
// Remove duplicates
arr = arr.filter((obj, pos, arr) => {
    return arr.map(mapObj => mapObj['contact_id']).indexOf(obj['contact_id']) === pos;
});

当代码运行时,有没有更好的方法?比如说,不用将arr变量设置两次


任何帮助都将不胜感激。

正如其他回复所指出的,您使用
sort()
函数是不合适的。传递给sort的函数应返回大于或小于0的数字,而不是布尔值。也就是说,如果你想继续你目前的方法,你可以像这样把你的两个陈述连在一起:

let arr = [
  {
    id: 1,
    contact_id: 2,
    some_field: true
  },
  {
    id: 2,
    contact_id: 3,
    some_field: true
  },
  {
    id: 3,
    contact_id: 4,
    some_field: false
  },
  {
    id: 4,
    contact_id: 3,
    some_field: true
  },
  {
    id: 5,
    contact_id: 4,
    some_field: false
  }
];

arr = arr.sort((a, b) => b.id > a.id).filter((obj, pos, arr) => {
  return (
    arr.map(mapObj => mapObj["contact_id"]).indexOf(obj["contact_id"]) === pos
  );
});

console.log(arr);

我不太确定我有多喜欢这个解决方案——代码的读者似乎很难理解。这就是说,它肯定会按照您的特定测试用例的预期工作(尽管如上所述,它可能不会与其他测试用例一起工作)-您可以看到它的实际应用

传递给的比较函数应返回一个数字,而不是true或false

您可以在排序之前映射数组,使原始数组保持原样。然后按联系人id第一和id第二排序。这允许您一次性删除重复项。按正确顺序再次排序:

const组织=[
{
id:1,
联系电话:2,
有些人认为这是真的
},
{
id:2,
联系电话:3,
有些人认为这是真的
},
{
id:3,
联系电话:4,
某些字段:false
},
{
id:4,
联系电话:3,
有些人认为这是真的
},
{
id:5,
联系电话:4,
某些字段:false
}
];
console.log(
org.map(x=>x)//排序使数组变异,这将防止它变异
.sort((a,b)=>a.contact_id-b.contact_id | | b.id-a.id)//先按联系人_id排序,然后按id排序
.减少(
([结果,上次],当前)=>
(last.contact\u id==当前.contact\u id)
?[结果,当前]
:[result.concat(当前),当前],
[[],{}]//result和last的初始值
)[0]。排序((a,b)=>b.id-a.id)//按id排序

)
如果您可以跟踪唯一的联系人ID,您可以执行以下操作

const arr=[{
id:1,
联系电话:2,
有些人认为这是真的
},
{
id:2,
联系电话:3,
有些人认为这是真的
},
{
id:3,
联系电话:4,
某些字段:false
},
{
id:4,
联系电话:3,
有些人认为这是真的
},
{
id:5,
联系电话:4,
某些字段:false
}
];
const contactIds={};
console.log(arr.sort)((a,b)=>{
返回a.id==b.id?0:a.id>b.id?-1:1;
}).map((obj)=>{
如果(!contactId[obj.contact_id]){
ContactId[obj.contact_id]=真;
返回obj;
}

}).filter((项)=>项!==未定义))请注意,首先,此代码有几个问题:

  • 这不是
    排序
    的工作方式。如果第一个值分别小于、大于或等于第二个值,则传递给sort的函数应返回负数、正数或零。虽然它似乎适用于您的特定测试用例,但返回布尔值是个坏主意

  • 这是一种收集唯一值的非常痛苦的方式。在每一次
    筛选
    迭代中,您都会重建整个密钥列表。然后,对于每一个,您都会扫描该列表,检查当前值是否包含在内。总之,使用
    集合
    来存储密钥,并在将其添加到输出之前测试该集合是否具有给定的密钥,这将非常干净


虽然Sreekath和HMR的答案很好,但我是函数式编程库的忠实粉丝。(免责声明:我是它的作者之一。)我倾向于从简单、可重用的函数的角度来思考

当我想到如何解决这个问题时,我是用拉姆达的观点来思考的。我可能会这样解决这个问题:

// Sort by latest to oldest activity
arr = arr.sort((a, b) => b.id > a.id);
// Remove duplicates
arr = arr.filter((obj, pos, arr) => {
    return arr.map(mapObj => mapObj['contact_id']).indexOf(obj['contact_id']) === pos;
});
const{pipe,sortBy,prop,reverse,uniqBy}=R
const convert=管道(
sortBy(prop('id')),
相反,
uniqBy(道具(“联系人id”))
)
const arr=[{“联系人id”:2,“id”:1,“某些字段”:true},{“联系人id”:3,“id”:2,“某些字段”:true},{“联系人id”:4,“id”:3,“某些字段”:false},{“联系人id”:3,“id”:4,“某些字段”:true},{“联系人id”:4,“id”:5,“某些字段”:false}]
console.log(转换(arr))
您可以使用
数组#reduce
为每个
联系人id
创建一个具有不同
联系人id
和最高
id
的对象。然后使用
Object.values()
,从该对象获取所有值并对其排序

const arr=[{id:1,contact_id:2,some_field:true},{id:2,contact_id:3,some_field:true},{id:3,contact_id:4,some_field:false},{id:4,contact_id:3,some_field:true},{id:5,contact_id:4,some_field:false},
结果=对象值(arr.reduce((r,o)=>{
r[o.contact_id]=r[o.contact_id]?(r[o.contact_id].idb.id-a.id);

控制台日志(结果)好的,排序会在适当的位置对数组进行变异,因此您不需要将结果返回到变量以过滤“arr”。“代码运行时,有没有更好的方法来进行此操作?”对于代码审阅,请询问in同意将此移到codereview。代码片段中存在几个bug请注意,
sort
不是这样工作的。如果第一个值分别小于、大于或等于第二个值,则传递给
sort
的函数应返回负数、正数或零。@henry感谢您提供的链接。值得注意的是,排序不正确。(如果
b.id
,比较器返回0,将值标识为“相等”。)