如何解决如何通过特定但深度嵌套的属性值对复杂数据结构的数组项进行排序?
这是我的数组,我有一个对象,然后计算 Id 的重复次数,例如第一个对象的 Id 2 重复了 3 次。
[{
Id: 1,Info: "Info",Category: [
{ Id: 2,count: 3 },{ Id: 4,count: 1 },{ Id: 8,{ Id: 18,{ Id: 9,{ Id: 3,],},{
Id: 2,Info: "Info 2",count: 2 },{ Id: 21,{
Id: 3,Info: "Info 3",Category: [
{ Id: 4,{ Id: 11,}]
现在我需要根据 Id 对这个数组进行排序,例如数字“9”,所以如果第一个对象的 id 为 9 的 Maximus 计数将是第一个,其他对象减去计数将在下面,像这样,数字 9 将是一个随机数。
[{
Id: 2,{
Id: 1,}]
解决方法
使用Array.prototype.sort需要根据OP的要求写a function which compares two array/list items。
在项目相等的情况下,此类比较器应返回大于零或小于零或零本身的数值。
因此需要找到两个不同的计数,每个项目一个 count
,将通过使用额外提供的 Category
值搜索项目的 id
数组来找到。
为了保持比较函数的可重用性,它被实现为 allows a context to be bound to it 的函数,在 OP 的情况下,它是一个具有 id
特征的对象正在寻找......例如类似 ... { id: 9 }
或 { id: 4 }
...
function compareByBoundIdCountOfItemCategoryList(a,b) {
const { id } = this;
const aCount = a.Category.find(ctgry => ctgry.Id === id)?.count ?? -1;
const bCount = b.Category.find(ctgry => ctgry.Id === id)?.count ?? -1;
// in case of equal counts compare the `Category` array's lengths'.
return (bCount - aCount) || (b.Category.length - a.Category.length);
}
const sampleList = [{
Id: 1,Info: "Info",Category: [
{ Id: 2,count: 3 },{ Id: 4,count: 1 },{ Id: 8,{ Id: 18,{ Id: 9,{ Id: 3,],},{
Id: 2,Info: "Info 2",count: 2 },{ Id: 21,{
Id: 3,Info: "Info 3",Category: [
{ Id: 4,{ Id: 11,}];
console.log(
'{ id: 9 } ...',sampleList
.sort(compareByBoundIdCountOfItemCategoryList.bind({ id: 9 }))
);
console.log(
'{ id: 4 } ...',sampleList
.sort(compareByBoundIdCountOfItemCategoryList.bind({ id: 4 }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
正如其中一条评论指出的那样,由于使用 compareByBoundIdCountOfItemCategoryList
函数,上述代码至少需要 节点 14.0.0 Optional Chaining Operator / ?.
和 Nullish Coalescing Operator / ??
。
为了让脚本不被破坏,必须更换一行...
... aCount = a.Category.find(ctgry => ctgry.Id === id)?.count ?? -1;
...使用这个替代...
... aCount = (a.Category.find(ctgry => ctgry.Id === id) || { count: -1 }).count;
function compareByBoundIdCountOfItemCategoryList(a,b) {
const { id } = this;
const aCount = (
a.Category.find(ctgry => ctgry.Id === id) ||
{ count: -1 }
).count;
const bCount = (
b.Category.find(ctgry => ctgry.Id === id) ||
{ count: -1 }
).count;
// in case of equal counts compare the `Category` array's lengths'.
return (bCount - aCount) || (b.Category.length - a.Category.length);
}
const sampleList = [{
Id: 1,sampleList
.sort(compareByBoundIdCountOfItemCategoryList.bind({ id: 4 }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
我发现这种格式比 Peter Seliger 的答案更简单。在创建传递给 sort
的比较器函数时,我们简单地将搜索到的 id 存储在一个闭包中:
const byCategoryCount = (categoryId) => ({Category: c1},{Category: c2}) =>
(c2 .find (({Id}) => Id === categoryId) ?.count ?? -1) -
(c1 .find (({Id}) => Id === categoryId) ?.count ?? -1)
const input = [{Id: 1,Category: [{Id: 2,count: 3},{Id: 4,count: 1},{Id: 8,{Id: 18,{Id: 9,{Id: 3,count: 1}]},{Id: 2,count: 2},{Id: 21,Category: [{Id: 4,{Id: 11,count: 1}]}]
console .log (input .sort (byCategoryCount (9)))
.as-console-wrapper {max-height: 100% !important; top: 0}
如果您的环境中没有可用的空合并运算符,则此变体并不会更糟:
const byCategoryCount = (categoryId) => ({Category: c1},{Category: c2}) =>
(c2 .find (({Id}) => Id === categoryId) || {count: -1}) .count -
(c1 .find (({Id}) => Id === categoryId) || {count: -1}) .count
我们也可以选择编写一个包装函数,它返回一个排序的版本而不改变原始列表。它可能看起来像这样:
const sortByCategoryCount = (categoryId,xs) =>
[... xs] .sort (byCategoryCount (categoryId))
但那时我们可能会开始怀疑辅助函数是否为我们提供了任何东西,我们可能会选择重构为
const sortByCategoryCount = (categoryId,xs) =>
[... xs] .sort (({Category: c1},{Category: c2}) =>
(c2 .find (({Id}) => Id === categoryId) || {count: -1}).count -
(c1 .find (({Id}) => Id === categoryId) || {count: -1}).count
)
,
这应该对你有用sortByCount
:
var my_arr = [{
Id: 1,}];
function sortByCount(arr,targetId){
var arr_temp = [];
arr.forEach(el => {
var elem = el.Category.filter(e => e.Id === targetId)[0];
var value = elem ? elem.count : -1;
arr_temp.push({
value: value,obj: el
});
});
arr_temp.sort((a,b)=> b.value - a.value);
return arr_temp.map(el => el.obj);
}
var sortedArr = sortByCount(my_arr,9);
console.log(sortedArr)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。