我有一大堆物件,類似于:
[
{
id: "some_id",
timestamp: 12345
},
{
id: "some_other_id",
timestamp: 12347
},
{
id: "some_id",
timestamp: 12346
},
{
id: "some_other_id",
timestamp: 12348
},
...
]
我想以某種方式對陣列進行排序,即陣列中有物件的“部分”,具體取決于物件具有的 ID。在每個部分內,物件應根據時間戳升序排列。部分本身也應根據部分的第一個時間戳進行排序。所以陣列應該是這樣的:
[
// section: some_id
{
id: "some_id",
timestamp: 12345
},
{
id: "some_id",
timestamp: 12348
},
// section: some_other_id, comes ofter some_id section because 12346 > 12345
{
id: "some_other_id",
timestamp: 12346
},
{
id: "some_other_id",
timestamp: 12347
},
...
]
還應該可以在函式中選擇升序/降序。現在我有這個:
elements.sort((a, b) => {
if (a.id === b.id) {
if (sortAscending) {
return a.timestamp > b.timestamp ? -1 : 1;
} else {
return a.timestamp > b.timestamp ? 1 : -1;
}
} else {
return a.id.localeCompare(b.id);
}
})
但是,這不會正確地對部分進行排序。有任何想法嗎?
uj5u.com熱心網友回復:
這將需要兩次遍歷陣列,因為您無法按部分排序,直到您知道部分的順序應該是什么并且您不知道這一點,直到您看到所有部分并因此知道最低或最高的是什么時間戳適用于每個部分(取決于您是進行升序還是降序)。
因此,可能有意義的是進行第一遍收集每個部分的極值并將其存盤到 Map 物件中,您可以將其用作部分排序索引。然后,您可以運行.sort(). 如果部分相同,則按時間戳排序。如果部分不同,則按部分索引中的值排序。
function sortByIdAndTimestamp(data, sortAscending = true) {
// create a Map object where keys are id values and values are the extreme
// timestamp for that id
const extremeTimestamp = new Map();
for (let item of data) {
if (testExtreme(item.timestamp, extremeTimestamp.get(item.id), sortAscending)) {
extremeTimestamp.set(item.id, item.timestamp);
}
}
// now just do a dual key sort
data.sort((a, b) => {
let result;
if (a.id === b.id) {
// if id is the same, just sort by timestamp
result = b.timestamp - a.timestamp;
} else {
// if id is not the same, sort by the extreme timestamp of the id
result = extremeTimestamp.get(b.id) - extremeTimestamp.get(a.id);
}
if (sortAscending) {
result = -result;
}
return result;
});
return data;
}
function testExtreme(val, extremeSoFar, sortAscending) {
// determine if this id's timestamp is more extreme
// than what we already have for that section
return (extremeSoFar === undefined) || (sortAscending ?
val < extremeSoFar :
val > extremeSoFar);
}
const sampleData = [{
id: "some_id",
timestamp: 12345
},
{
id: "some_other_id",
timestamp: 123
},
{
id: "some_id",
timestamp: 12346
},
{
id: "some_other_id",
timestamp: 99999
},
{
id: "yet_another_id",
timestamp: 1
},
{
id: "yet_another_id",
timestamp: 90000
},
];
sortByIdAndTimestamp(sampleData, true);
console.log(sampleData);
注意:當您說要按升序或降序排序時,我假設您的意思是對部分和時間戳都如此。因此,升序排序將首先具有最低的時間戳部分,然后每個部分中的專案將按時間戳從低到高排序。而且,降序排序將首先具有最高的時間戳部分,然后每個部分中的專案將按時間戳從高到低排序。
uj5u.com熱心網友回復:
你將無法以一種方式做到這一點。由于您不知道最小值是多少,因此必須執行多個步驟。
一種方法是組合、排序,然后根據最低的排序。
const data = [
{
id: "a",
timestamp: 4
},
{
id: "b",
timestamp: 3
},
{
id: "a",
timestamp: 2
},
{
id: "b",
timestamp: 1
},
];
const x = data.reduce((a,o) => {
a[o.id] = a[o.id] || [];
a[o.id].push(o);
return a;
}, {});
const v = Object.values(x);
v.forEach(x => x.sort((a,b) => a.timestamp > b.timestamp ? 1 : -1))
v.sort((a,b)=>a[0].timestamp > b[0].timestamp ? 1 : -1);
const sorted = v.flat();
console.log(sorted);
另一種方法是找到最低的,然后用它排序。
const data = [{
id: "a",
timestamp: 4
},
{
id: "b",
timestamp: 3
},
{
id: "a",
timestamp: 2
},
{
id: "b",
timestamp: 1
},
];
const smallest = data.reduce((a ,o) => {
a[o.id] = Math.min(a[o.id] === undefined? Number.POSITIVE_INFINITY : a[o.id], o.timestamp);
return a;
}, {});
data.sort((a,b) => {
return a.id === b.id ?
(a.timestamp > b.timestamp ? 1 : -1)
: smallest[a.id] > smallest[b.id] ? 1 : -1;
})
console.log(data);
uj5u.com熱心網友回復:
編輯:如果我正確理解你需要什么,這是一種方法
const data = [{
id: "some_id",
timestamp: 12348
},
{
id: "some_other_id",
timestamp: 12346
},
{
id: "some_id",
timestamp: 12345
},
{
id: "some_other_id",
timestamp: 12347
},
{
id: "X_other_id",
timestamp: 12343
},
{
id: "other_id",
timestamp: 12349
}
]
const groupById = (acc, item) => {
acc[item.id] ? acc[item.id].push(item) : acc[item.id] = [item];
return acc;
};
function sort(arr, bool) {
const groups = Object.values(arr.reduce(groupById, {}))
.map(group => group.sort((a, b) => bool ? a.timestamp - b.timestamp : b.timestamp - a.timestamp))
.sort((a, b) => bool ? a[0].timestamp - b[0].timestamp : b[0].timestamp - a[0].timestamp);
return groups.flat()
}
console.log(sort(data, ascending = true))
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/347366.html
標籤:javascript 节点.js 数组 排序
