У меня есть такой массив объектов:
let messageScoreData = {
messagescore: [
{
userid: "5bacc8c6563a882a1ca7756a",
score: 2605.4
},
{
userid: "5bacc98431481e0520856df8",
score: 1013.2
},
{
userid: "5bc6d0bb26f1bb1b44a790c6",
score: 41
},
{
userid: "5bc6d0bb26f1bb1b44a790c9",
score: 29
}
],
messagescorebefore: [
{
userid: "5bacc8c6563a882a1ca7756a",
score: 3754
},
{
userid: "5bacc98431481e0520856df8",
score: 1259.8
},
{
userid: "5bc6d0bb26f1bb1b44a790c6",
score: 98
},
{
userid: "5bced078d62b321d08f012af",
score: 22
},
{
userid: "5bcec1ad11302529f452b31e",
score: 6
},
{
userid: "5c10afec8c587d2fac8c356e",
score: 6
},
{
userid: "5c07b7f199848528e86e9359",
score: 3
},
{
userid: "5bed1373f94b611de4425259",
score: 2
},
{
userid: "5c21ccff833a5006fc5a98af",
score: 2
},
{
userid: "5c21ccff82e32c05c4043410",
score: 1
}
]
};
Теперь мы предоставим значение веса-возраста, т.е. массив messagescorebefore имеет значение 0,4, а значение messagescore - 0,6; Для этого у меня есть алгоритм, который упорядочивает значение со значением веса-возраста. т.е.
var result = messageScoreData;
var columns = [
{
name: "messagescorebefore",
value: 0.4
},
{
name: "messagescore",
value: 0.6
}
];
var total = {};
for (let column of columns) {
for (let userid of result[column.name]) {
var alphabet = userid.userid;
if (total[alphabet]) {
total[alphabet] += column.value;
} else {
total[alphabet] = column.value;
}
}
}
const valueholder = Object.keys(total)
.map(key => ({ name: key, value: total[key] }))
.sort((f, s) => s.value - f.value);
console.info(valueholder);
По этому алгоритму вывод:
[ { name: '5bacc8c6563a882a1ca7756a', value: 1 },
{ name: '5bc6d0bb26f1bb1b44a790c6', value: 1 },
{ name: '5bacc98431481e0520856df8', value: 1 },
{ name: '5bc6d0bb26f1bb1b44a790c9', value: 0.6 },
{ name: '5bcec1ad11302529f452b31e', value: 0.4 },
{ name: '5bced078d62b321d08f012af', value: 0.4 },
{ name: '5c07b7f199848528e86e9359', value: 0.4 },
{ name: '5bed1373f94b611de4425259', value: 0.4 },
{ name: '5c21ccff833a5006fc5a98af', value: 0.4 },
{ name: '5c21ccff82e32c05c4043410', value: 0.4 },
{ name: '5c10afec8c587d2fac8c356e', value: 0.4 } ]
Проблема заключается в идентификаторе пользователя: «5bacc98431481e0520856df8» будет занимать вторую позицию в обоих массивах, но после окончательного расчета это окажется под 3-ей позицией, что неверно. ожидаемый результат будет таким:
[ { name: '5bacc8c6563a882a1ca7756a', value: 1 },
{ name: '5bacc98431481e0520856df8', value: 1 },
{ name: '5bc6d0bb26f1bb1b44a790c6', value: 1 },
{ name: '5bc6d0bb26f1bb1b44a790c9', value: 0.6 },
{ name: '5bced078d62b321d08f012af', value: 0.4 },
{ name: '5bcec1ad11302529f452b31e', value: 0.4 },
{ name: '5c10afec8c587d2fac8c356e', value: 0.4 },
{ name: '5c07b7f199848528e86e9359', value: 0.4 },
{ name: '5bed1373f94b611de4425259', value: 0.4 },
{ name: '5c21ccff833a5006fc5a98af', value: 0.4 },
]
Любая помощь очень ценится для этого. заранее спасибо



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Наблюдаемое поведение является ожидаемым, поскольку вы сортируете ценности по убыванию: .sort((f, s) => s.value - f.value);. Из вашего примера кажется, что вы хотите лексикографически отсортировать записи по именам. В этом случае вам следует отсортировать по именам:
const valueholder = Object.keys(total)
.map(key => ({ name: key, value: total[key] }))
.sort((f, s) => f.name.localeCompare(s.name));
Если вы хотите отсортировать их в первую очередь по значениям (по убыванию) и во вторую очередь по именам (по возрастанию), выполните:
const valueholder = Object.keys(total)
.map(key => ({ name: key, value: total[key] }))
.sort((f, s) => s.value - f.value || f.name.localeCompare(s.name));
В этом случае, если две записи имеют одинаковое значение, разница s.value - f.value будет равна 0. Поскольку это ложное значение, f.name.localeCompare(s.name) будет оцениваться, эффективно сортируя значения лексикографически по их имени.
Если вы хотите отсортировать записи по их значениям, но сохранить исходный порядок записей с тем же значением, вы можете сделать следующее:
const entries = Object.keys(total)
.map(key => ({ name: key, value: total[key] }))
const valueholder = entries.sort((f, s) => s.value - f.value || arr.indexOf(f) - arr.indexOf(s));
Причина, по которой нам нужно явно выполнять сортировку в исходном порядке, заключается в том, что встроенный алгоритм сортировки не является (гарантированно) стабильным. Обратите внимание, что приведенная выше сортировка не очень эффективна, поскольку мы используем indexOf. Я оставляю это в качестве упражнения, чтобы сначала пройти по массиву и собрать все индексы на карте, которая сопоставляет имена с индексами. Таким образом, при сортировке вы можете искать индексы, а не вычислять их.
Фактически, вы хотите сохранить относительный порядок элементов. нормальная функция сортировки не гарантирует сохранения относительного порядка. поэтому нам нужны некоторые уловки, чтобы поддерживать относительный порядок, как показано ниже.
let messageScoreData = {
messagescore: [
{
userid: "5bacc8c6563a882a1ca7756a",
score: 2605.4
},
{
userid: "5bacc98431481e0520856df8",
score: 1013.2
},
{
userid: "5bc6d0bb26f1bb1b44a790c6",
score: 41
},
{
userid: "5bc6d0bb26f1bb1b44a790c9",
score: 29
}
],
messagescorebefore: [
{
userid: "5bacc8c6563a882a1ca7756a",
score: 3754
},
{
userid: "5bacc98431481e0520856df8",
score: 1259.8
},
{
userid: "5bc6d0bb26f1bb1b44a790c6",
score: 98
},
{
userid: "5bced078d62b321d08f012af",
score: 22
},
{
userid: "5bcec1ad11302529f452b31e",
score: 6
},
{
userid: "5c10afec8c587d2fac8c356e",
score: 6
},
{
userid: "5c07b7f199848528e86e9359",
score: 3
},
{
userid: "5bed1373f94b611de4425259",
score: 2
},
{
userid: "5c21ccff833a5006fc5a98af",
score: 2
},
{
userid: "5c21ccff82e32c05c4043410",
score: 1
}
]
};
var result = messageScoreData;
var columns = [
{
name: "messagescorebefore",
value: 0.4
},
{
name: "messagescore",
value: 0.6
}
];
var total = [];
for (let column of columns) {
for (let userid of result[column.name]) {
var alphabet = userid.userid;
if (total[alphabet]) {
total[alphabet] += column.value;
} else {
total[alphabet] = column.value;
}
}
}
let res = Object.keys(total).map((k, idx) => {
return {
name: k,
value: total[k],
index: idx
}
})
var output = res.sort((f, s) => {
if (s.value < f.value) return -1;
if (s.value > f.value) return 1;
return f.index - s.index
})
console.info("output : ", output)@ Кевин, да, мы справимся.
Если вы ищете стабильная сортировка, то есть сохраняя исходный порядок элементов массива с равным значением, вам нужно добавить сравнение индексов ключевого массива (при условии, что это имеет правильный порядок):
const keys = Object.keys(total);
const valueholder = keys
.map(key => ({ name: key, value: total[key] }))
.sort((f, s) => s.value - f.value || keys.indexOf(f.name) < keys.indexOf(s.name));
Вы можете упростить это решение до
var output = res.sort((f, s) => s.value - f.value || f.index - s.index).