Javascript按字母顺序排序并将所有的双精度字符移动到数组的末尾
我正在尝试按属性对对象数组进行排序。我运行:Javascript按字母顺序排序并将所有的双精度字符移动到数组的末尾,javascript,arrays,sorting,object,Javascript,Arrays,Sorting,Object,我正在尝试按属性对对象数组进行排序。我运行: array.sort(function(a, b){ var textA = a.name.toUpperCase(); var textB = b.name.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1: 0 }); 它似乎适用于任何没有重复项的对象,但是,一旦有重复项,它就会将它们全部推到数组的末尾,而不仅仅是多余项 例如: [ {n
array.sort(function(a, b){
var textA = a.name.toUpperCase();
var textB = b.name.toUpperCase();
return (textA < textB) ? -1 : (textA > textB) ? 1: 0
});
它似乎适用于任何没有重复项的对象,但是,一旦有重复项,它就会将它们全部推到数组的末尾,而不仅仅是多余项
例如:
[
{name: 'Amy'},
{name: 'Amy'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Dan'},
{name: 'Dave'}
{name: 'Joe'},
{name: 'Joe'}
]
[
{name: 'Amy'},
{name: 'Amy'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Dan'},
{name: 'Dave'},
{name: 'Joe'},
{name: 'Joe'},
{name: 'Joe'},
]
预期产出:
- 艾米
- 克拉克
- 丹
- 戴夫
- 乔
- 艾米
- 克拉克
- 乔
- 丹
- 戴夫
- 艾米
- 艾米
- 克拉克
- 克拉克
- 乔
- 乔
array.sort(function(a,b){
if(a.name === b.name){return -1}
return 1;
});
我感觉array.sort和compare函数可以处理这个问题,但是我一直在使用返回值0,-1,1,似乎无法让它像我希望的那样完全工作
更新
预期结果标准:
如果一个对象具有相同的名称,则副本应位于数组的末尾。例如,如果有两个“Amy”,则其中一个位于数组的开头,而副本则位于数组的结尾。因此,所有第一次出现的名称都将在数组的开头,并且所有的双精度、三精度等将在数组的末尾重新排序。这样它就可以潜在地安排多个项目
例如:
[
{name: 'Amy'},
{name: 'Amy'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Dan'},
{name: 'Dave'}
{name: 'Joe'},
{name: 'Joe'}
]
[
{name: 'Amy'},
{name: 'Amy'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Clark'},
{name: 'Dan'},
{name: 'Dave'},
{name: 'Joe'},
{name: 'Joe'},
{name: 'Joe'},
]
预期结果:
艾米
克拉克
丹
戴夫
乔
艾米-重复
克拉克-重复
乔-重复
克拉克有第三个
乔有第三个
如您所见,它按字母顺序排列所有名称的第一次出现。然后按字母顺序排列第二次出现,然后是第三次出现。直到解决所有重复项
在评论中讨论之后,我的理解是,不能仅在array.sort函数中完成。使用比较函数单独排序对于单个或分组双精度似乎很好,但不适合将双精度放在数组的末尾 您的比较器功能不正确。该功能必须:
- 当第一个参数应在第二个参数之前排序时,返回一个负数李>
- 当第一个参数应在第二个参数之后排序时,返回一个正数李>
- 当两个项具有等效的排序键时,返回零
.localeCompare()
函数,该函数返回您所需的结果:
array.sort(function(a, b) { return a.name.localeCompare(b.name); });
从您的“预期输出”来看,您的订购标准不明确。在任何情况下,排序比较器,无论它做什么,都必须是一致的:当两个项以任意顺序传递给它时,函数应该报告相同的顺序
编辑如果原始顺序具有某种语义含义,并且“double”(我称之为“duplicates”)应该在数组中进一步排序,则可以向捕获原始状态的每个对象添加另一个属性:
var keyMap = {};
array.forEach(function(item) {
if (item.name in keyMap)
item.position = ++keyMap[item.name];
else
keyMap[item.name] = item.position = 1;
});
现在您可以排序:
array.sort(function(a, b) {
var c = a.position - b.position;
if (c) return c;
return a.name.localeCompare(b.name);
});
如果“位置”值相同,则项目将按名称排序。原始数组中重复的项将在未重复的项之后排序(重复的项将在这些项之后排序,以此类推)。您可以使用临时对象和同一组数组的哈希表。从中获取用作排序组的数组的长度
排序与组和索引一起进行
结果与已排序临时数组的索引映射
Tge第一部分生成一个数组,其中包含原始数组及其组的索引,该索引是从将值推入同一组中获取的。事实上,我们需要在组的推进后得到数组长度的oly。如果同一组中有更多项目,则稍后将对这些项目进行排序
然后按组和索引对上述给定数组进行排序,两者都是升序
在最后一部分,一个新数组被映射为排序数组的索引值
var数组=[{name:'Amy'},{name:'Amy'},{name:'Dan'},{name:'Joe'},{name:'Joe'}],
groups=Object.create(空),
结果=数组
//仅当名称应按升序排列时,才需要此部分
//为了保持给定的顺序,请在下一次注释之前删除该零件
.排序(功能(a、b){
返回a.name.localeCompare(b.name);
})
//如有必要,将其移到此处
.map(函数(a,i){
返回{index:i,group:(groups[a.name]=groups[a.name]| |[]).push(0)};
})
.排序(功能(a、b){
返回a.group-b.group | a.index-b.index;
})
.map(功能(o){
返回数组[o.index];
});
控制台日志(结果)代码>
.as console wrapper{max height:100%!important;top:0;}
您可以首先加入重复项并计算它们的出现次数:
const array = [
{name: 'Amy'},
{name: 'Amy'},
{name: 'Dan'},
{name: 'Joe'},
{name: 'Joe'}
];
const counted = [], byName = {};
for(var {name} of array){
if(byName[name]){
byName[name].count++;
}else{
counted.push(byName[name] = {name, count:1});
}
}
既然名称是唯一的,我们可以按字母顺序对它们进行排序:
counted.sort((a, b) => a.name.localeCompare(b.name));
最后,我们需要再次传播这些名称:
const result = [];
while(counted.length){
for(var i = 0; i < counted.length; i++){
const name = counted[i];
result.push(name.name);
name.count--;
if(!name.count){
counted.splice(i, 1);
i--;
}
}
}
const result=[];
while(计算长度){
对于(变量i=0;i
函数比较示例(a、b){
如果(a>b){
返回1;
}否则如果(a0?附件[附件长度-1]:空
if(上一个值和比较值)(上一个值,当前)==0){
等级=上一等级+1
}
acc.push({value:curr,rank:rank});
返回acc
},
function compareSimple(a, b) {
if (a > b) {
return 1;
} else if (a < b) {
return -1;
}
return 0;
}
function compareAlphabetic(a, b) {
return compareSimple(a.name.toUpperCase(), b.name.toUpperCase());
}
let input = [
{ name: 'Amy' },
{ name: 'Amy' },
{ name: 'Clark' },
{ name: 'Clark' },
{ name: 'Dan' },
{ name: 'Clark' },
{ name: 'Dave' },
{ name: 'Joe' },
{ name: 'Joe' },
];
let output = input
.sort(compareAlphabetic)
.reduce(function(acc, curr) {
let rank = 0
let prev = acc.length > 0 ? acc[acc.length-1] : null
if (prev && compareAlphabetic(prev.value, curr) === 0) {
rank = prev.rank + 1
}
acc.push({ value: curr, rank: rank });
return acc
}, [])
// now we have an array like this
// [
// { value: Amy, rank: 0},
// { value: Amy, rank: 1},
// { value: Clark, rank: 0},
// ...]
// Now let's sort it by rank AND name
.sort(function(a, b) {
let result = compareSimple(a.rank, b.rank);
if (result !== 0) {
return result;
}
return compareAlphabetic(a.value, b.value);
})
// we have to unpack it all back:
.map(function(obj) {
return obj.value;
});
console.log(output);
// [ { name: 'Amy' },
// { name: 'Clark' },
// { name: 'Dan' },
// { name: 'Dave' },
// { name: 'Joe' },
// { name: 'Amy' },
// { name: 'Clark' },
// { name: 'Joe' },
// { name: 'Clark' } ]