Массив значений объектов с некоторым значением возраста веса не входит в правильную последовательность

У меня есть такой массив объектов:

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 },
]

Любая помощь очень ценится для этого. заранее спасибо

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
78
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Наблюдаемое поведение является ожидаемым, поскольку вы сортируете ценности по убыванию: .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)

Вы можете упростить это решение до var output = res.sort((f, s) => s.value - f.value || f.index - s.index).

Kevin 28.12.2018 18:14

@ Кевин, да, мы справимся.

varatharajan 28.12.2018 18:23

Если вы ищете стабильная сортировка, то есть сохраняя исходный порядок элементов массива с равным значением, вам нужно добавить сравнение индексов ключевого массива (при условии, что это имеет правильный порядок):

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));

Другие вопросы по теме