如何在JavaScript中仅使用一个变量声明对数组进行正确排序并删除重复项?
所以我有一个工作代码,它将数组从最高id排序到最低id,然后删除重复项 假设我们有一系列的活动:如何在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: 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,将值标识为“相等”。)