Return 对数组中的唯一值进行排序,但如果计数相等,则 return 个值按顺序排列
Return sorted unique values from array, but if count is equal, return values in order
我正在创建一个函数,它接受一个未排序的整数数组和 returns 一个按频率排序的唯一整数数组。但是,如果整数具有相同的频率,它们将按输入数组的原始顺序 returned。这是我当前的功能:
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]] ++;
} else {
counter[arr[i]] = 1;
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a]
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
所以对于这样的数组:
arr = [1, 3, 2, 1, 5, 2, 1, 4]
函数应该return:
[1,2,3,5,4]
但是,我的函数是对 5 和 4 进行排序,并且是 returning:
[1,2,3,4,5]
请帮忙!
如果频率相等,可能会添加一个附加条件以实际排序在原始数组索引之后:
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a] || arr.indexOf(+a)-arr.indexOf(+b)
});
这种重新排序的原因是使用 Object.keys()
时数字对象属性将按顺序排列。
不要将 counter
定义为对象,而是使用 Map
,这将保留插入顺序:
function uniqueUnionSorted(arr) {
var counter = new Map();
for(var i=0; i<arr.length; i++) {
counter.set(arr[i], (counter.get(arr[i]) || 0) + 1);
}
// Spreading the Map will produce an array of pairs
var sortedNumbers = [...counter].sort(function(a,b) {
return b[1] - a[1]; // sort by count
}).map(a => a[0]); // only keep the values, not the counts
return sortedNumbers; // Map keys retain original type, so they remain numeric
}
arr = [1, 3, 2, 1, 5, 2, 1, 4]
console.log(uniqueUnionSorted(arr));
在计数器对象中,我们还可以保存每个元素的最低索引,这样我们就可以在排序数组中保留较低索引的元素。
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]].count ++;
} else {
counter[arr[i]] = {'count' : 1, 'index' : i}; //save lowest index of element
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b].count - counter[a].count || counter[a].index - counter[b].index;
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
console.log(uniqueUnionSorted([1, 3, 2, 1, 5, 2, 1, 4]));
https://jsfiddle.net/anLrwwfa/4/
这是另一种方法,您可以使用 Set 对象、存储频率的对象和保持原点不变的原始数组来执行此操作。它比当前流行的答案有点长,但我正在写它,所以我想我会把我的帽子扔进戒指。
function sortArr(arr) {
let uniqueValues = new Set();
let frequencies = new Object();
//add values to set object
arr.map((val) => uniqueValues.add(val));
//get frequencies of values
for (let val of uniqueValues) {
frequencies[val] = 0;
}
arr.map((val) => frequencies[val]++);
//sort by frequency, then sort by original placement in array
let sorted_arr = Array.from(uniqueValues).sort((a, b) => {
return frequencies[a] - frequencies[b];
}).sort((a, b) => {
return (frequencies[a] === frequencies[b]) ?
Array.from(uniqueValues).indexOf(a) - Array.from(uniqueValues).indexOf(b) :
b;
});
//return array
return sorted_arr;
};
sortArr([1, 3, 2, 1, 5, 2, 1, 4]); //1,2,3,5,4
编辑
稍微优化一下代码
我正在创建一个函数,它接受一个未排序的整数数组和 returns 一个按频率排序的唯一整数数组。但是,如果整数具有相同的频率,它们将按输入数组的原始顺序 returned。这是我当前的功能:
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]] ++;
} else {
counter[arr[i]] = 1;
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a]
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
所以对于这样的数组:
arr = [1, 3, 2, 1, 5, 2, 1, 4]
函数应该return:
[1,2,3,5,4]
但是,我的函数是对 5 和 4 进行排序,并且是 returning:
[1,2,3,4,5]
请帮忙!
如果频率相等,可能会添加一个附加条件以实际排序在原始数组索引之后:
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a] || arr.indexOf(+a)-arr.indexOf(+b)
});
这种重新排序的原因是使用 Object.keys()
时数字对象属性将按顺序排列。
不要将 counter
定义为对象,而是使用 Map
,这将保留插入顺序:
function uniqueUnionSorted(arr) {
var counter = new Map();
for(var i=0; i<arr.length; i++) {
counter.set(arr[i], (counter.get(arr[i]) || 0) + 1);
}
// Spreading the Map will produce an array of pairs
var sortedNumbers = [...counter].sort(function(a,b) {
return b[1] - a[1]; // sort by count
}).map(a => a[0]); // only keep the values, not the counts
return sortedNumbers; // Map keys retain original type, so they remain numeric
}
arr = [1, 3, 2, 1, 5, 2, 1, 4]
console.log(uniqueUnionSorted(arr));
在计数器对象中,我们还可以保存每个元素的最低索引,这样我们就可以在排序数组中保留较低索引的元素。
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]].count ++;
} else {
counter[arr[i]] = {'count' : 1, 'index' : i}; //save lowest index of element
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b].count - counter[a].count || counter[a].index - counter[b].index;
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
console.log(uniqueUnionSorted([1, 3, 2, 1, 5, 2, 1, 4]));
https://jsfiddle.net/anLrwwfa/4/
这是另一种方法,您可以使用 Set 对象、存储频率的对象和保持原点不变的原始数组来执行此操作。它比当前流行的答案有点长,但我正在写它,所以我想我会把我的帽子扔进戒指。
function sortArr(arr) {
let uniqueValues = new Set();
let frequencies = new Object();
//add values to set object
arr.map((val) => uniqueValues.add(val));
//get frequencies of values
for (let val of uniqueValues) {
frequencies[val] = 0;
}
arr.map((val) => frequencies[val]++);
//sort by frequency, then sort by original placement in array
let sorted_arr = Array.from(uniqueValues).sort((a, b) => {
return frequencies[a] - frequencies[b];
}).sort((a, b) => {
return (frequencies[a] === frequencies[b]) ?
Array.from(uniqueValues).indexOf(a) - Array.from(uniqueValues).indexOf(b) :
b;
});
//return array
return sorted_arr;
};
sortArr([1, 3, 2, 1, 5, 2, 1, 4]); //1,2,3,5,4
编辑 稍微优化一下代码