对象数组按某个属性的某个顺序连续排序
问题描述
按照数据中love这个属性去排序,而且这个顺序必须是“乒乓球、羽毛球、篮球”排序
原始数据如下:
const data = [ {
name: '李',
love: '篮球'
},
{
name: '李',
love: '乒乓球'
},
{
name: '李',
love: '羽毛球'
},
{
name: '张',
love: '乒乓球'
},
{
name: '张',
love: '羽毛球'
},
{
name: '张',
love: '篮球'
},
{
name: '吴',
love: '羽毛球'
},
{
name: '吴',
love: '乒乓球'
},
]
需要的结果数据如下:
const data = [ {
name: '李',
love: '乒乓球'
},
{
name: '李',
love: '羽毛球'
},
{
name: '李',
love: '篮球'
},
{
name: '张',
love: '乒乓球'
},
{
name: '张',
love: '羽毛球'
},
{
name: '张',
love: '篮球'
},
{
name: '吴',
love: '乒乓球'
},
{
name: '吴',
love: '羽毛球'
},
]
回答:
从题主给的结果数据来看,并不是单纯的按 love
来排序,而是「先按 name
再按 love
的双重排序」,而且
name
不是按字母序,而是按先后出现的顺序love
是按“乒乓球、羽毛球、篮球”的顺序
其中,按 name
出现序需要提前遍历数组,把顺序排出来;或者在排的过程中来产生(因为是顺序,可以在过程中来产生)。
下面这个例子是提前产生的
/** * 从给定的字符串数组生成序数映射表
* @param { string[] } list
* @returns
*/
function makeSerialsMap(list) {
return Object.fromEntries(list.map((v, i) => [v, i]));
}
/**
* 排序
*/
function sort(data) {
const nameSerials = (() => {
const dict = new Set();
const names = data
.map(({ name }) => {
if (dict.has(name)) { return undefined; }
dict.add(name);
return name;
})
.filter(name => name);
return makeSerialsMap(names);
})();
console.log(nameSerials); // { '李': 0, '张': 1, '吴': 2 }
// 为 3 个 love 依序关联一个数组,并形成查找表
const loveSerials = makeSerialsMap(["乒乓球", "羽毛球", "篮球"]);
console.log(loveSerials); // { '乒乓球': 0, '羽毛球': 1, '篮球': 2 }
return data
.sort((a, b) => {
// 先按姓名排序(这里暂时没按出现的先后顺序
const nameDiff = nameSerials[a.name] - nameSerials[b.name];
if (nameDiff) { return nameDiff; }
// 然后按 love 对应的序数来排序
return loveSerials[a.love] - loveSerials[b.love];
});
}
其中,生成 nameSerials
过程(IIFE 中)中的 names
可以简单地用一句话产生
const names = [...new Set(data.map(({ name }) => name))];
虽然(可能仅在某些环境下)效果还是如预期,但是 Set
本身不应保证排序,所以不同的 JS Runtime 实现有可能不同,所以不这样用。
另一种方法,在过程中产生 nameSerials
,其实就是在取序数的时候,检查如果这个 name
不存在于集合中,就把它保存进去,映射到一个“尾值”(一般可以用 Set.prototype.size
),并返回。具体代码就不写了,可以自己试试。
回答:
你的题目描述似乎存在问题,
如果按 「按照数据中love这个属性去排序,而且这个顺序必须是“乒乓球、羽毛球、篮球”排序」 实现的话
在线代码演示
但按你后面提供的第二份数据你的目的似乎是 「先将数据按 name 排序,然后再按数据中love这个属性去排序,而且这个顺序必须是“乒乓球、羽毛球、篮球”排序」
实现方案如下
在线代码演示
不过这里的排序是 李 吴 张 ,不清楚你第二份数据中的张排第二位是按照什么规则来的,需要你按照自己的规则稍微修改一下
回答:
const data = [ {
name: '李',
love: '篮球'
},
{
name: '李',
love: '乒乓球'
},
{
name: '李',
love: '羽毛球'
},
{
name: '张',
love: '乒乓球'
},
{
name: '张',
love: '羽毛球'
},
{
name: '张',
love: '篮球'
},
{
name: '吴',
love: '羽毛球'
},
{
name: '吴',
love: '乒乓球'
},
]
const map = data.reduce((map, item) => {
const { love } = item;
if (!map.get(love)) {
map.set(love, []);
}
map.get(love).push(item);
return map;
}, new Map());
const sortLove = ['乒乓球', '羽毛球', '篮球'];
const length = Math.max(...[...map.values()].map(item => item.length));
const result = [];
for(let i = 0; i < length; i++) {
sortLove.forEach(key => {
const item = map.get(key)?.[i];
if (item) {
result.push(item);
}
})
}
console.log(result);
回答:
const data = [ {
name: "李",
love: "篮球"
},
{
name: "李",
love: "乒乓球"
},
{
name: "李",
love: "羽毛球"
},
{
name: "张",
love: "乒乓球"
},
{
name: "张",
love: "羽毛球"
},
{
name: "张",
love: "篮球"
},
{
name: "吴",
love: "羽毛球"
},
{
name: "吴",
love: "乒乓球"
}
];
let res = [];
const sorts = ["乒乓球", "羽毛球", "篮球"];
while (data.length) {
sorts.forEach(item => {
const idx = data.findIndex(r => r.love == item);
idx > -1 && res.push(data.splice(idx, 1));
});
}
console.log(res);
以上是 对象数组按某个属性的某个顺序连续排序 的全部内容, 来源链接: utcz.com/p/935635.html