按两个最接近的字段排序JS数组

3
我将根据两个字段对数组进行排序,同时提供所需数字以进行排序。我尝试使用lodash库,但没有得到期望的结果。
例如:
const data = [
  {name: 'first', score: 22, average: 59},
  {name: 'second', score: 34, average: 83},
  {name: 'third', score: 40, average: 24},
  {name: 'fourth', score: 29, average: 49},
  {name: 'fifth', score: 23, average: 55}
];
// call function like this
sortByTwoFields({field:'score', number:21}, {field:'average', number:50}); 

期望的结果应该是:
const result = [
  {name: 'fifth', score: 23, average: 55},
  {name: 'fourth', score: 29, average: 49},
  {name: 'first', score: 22, average: 59},
  {name: 'third', score: 40, average: 24},
  {name: 'second', score: 34, average: 83}
];

任何想法都将不胜感激。

我想按照与我发送的数字最接近的结果对它们进行排序。 - Nate
我已经更新了问题,并附上了所需的结果。 - Nate
我正在尝试不优先考虑任何领域,而是让两个领域中最好/最接近的结果出现在顶部(降序)。 - Nate
1
您提供了不正确的预期结果。名为 fourth 的项目应该在名为 first 的项目之前,因为名为 fourth 的项目的距离等于9,而名为 first 的项目的距离等于10。 - Alexander Elgin
你对预期结果的想法是正确的,我已经在我的问题中修复了它。谢谢大家! - Nate
显示剩余4条评论
4个回答

1
如何简单地使用 lodash_.sortBy 函数呢?
可以使用以下代码: _.sortBy(data, [a=> Math.abs(a.score - 21), a=> Math.abs(a.average - 50)])
这样就足够了吗?
编辑:
如果你需要从多个地方调用此排序函数,并且需要按不同的字段(嵌套)进行排序,那么可以将其封装在一个函数中,动态准备迭代器并将其传递给 sortBy 函数。
下面是一个可行的示例:

var data = [
  {name: 'first', score: 22, average: 59},
  {name: 'second', score: 34, average: 83},
  {name: 'second', score: 34, average: 80},
  {name: 'third', score: 40, average: 24},
  {name: 'fourth', score: 29, average: 49},
  {name: 'fifth', score: 23, average: 55}
];

function sortByClosest(arr, ...fields) {
    //this will create array of callbacks, similar to what user in first example
    let iteratees = fields.map(f => o => Math.abs(f.number - o[f.field]));
    return _.sortBy(arr, iteratees);
}

//pass data for "arr" argument, and all other
//sort key/closest-value for fields array argument
var res = sortByClosest(data, {field:'score', number:21},{field:'average',number:50});

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

然而,可以使用更短的格式传递最接近值,例如{score: 21, average: 50},在这种情况下,生成迭代器的逻辑需要相应地进行调整,因此它将变为:

_.map(fields, (v,k)=> o=> Math.abs(v - o[k]))

您需要使用单个对象调用它(如上所示),这是该调用的方法:

sortByClosest(data, {score: 21, average: 50});


谢谢,这实际上是最简单的解决方案! - Nate
很高兴能够帮到你 :) - Koushik Chatterjee

0

你的期望结果似乎有点偏差,因为fourth的总差异为9,而first的总差异为10。下面的函数被调用为sortByTwoFields(data, {field:'score', number:21}, {field:'average', number:50})。如果想要优先考虑某个对象,可以添加weight属性,否则默认为1。

function sortByTwoFields (data, info1, info2) {
    if (! ("weight" in info1)) {
        info1.weight = 1;
    }
    if (! ("weight" in info2)) {
        info2.weight = 1;
    }
    return data.sort(function (a, b) {
        var adiff1 = a[info1.field] - info1.number;
        var adiff2 = a[info2.field] - info2.number;
        var bdiff1 = b[info1.field] - info1.number;
        var bdiff2 = b[info2.field] - info2.number;
        return Math.abs(adiff1) * info1.weight + Math.abs(adiff2) * info2.weight - Math.abs(bdiff1) * info1.weight - Math.abs(bdiff2) * info2.weight;
    });
}

0

您可以通过按任意数量的字段进行排序,而不仅仅是两个字段,轻松地将其变成通用的:

function sortByFields(objs, fields) {
  const diffToFields = obj =>
    _(fields).map(f => Math.abs(obj[f] - f.number)).sum();
  return _(objs).sortBy(diffToFields).value();
}

const sortedData = sortByFields(data, [
  {field: 'score', number: 21},
  {field: 'average', number: 50},
]);

您能提供一个使用案例吗? - Nate

0

我不认为你期望的结果是正确的,因为第四个数的总差值更小。

无论如何,该函数将计算给定值和数字之间的总差异,然后按照该总差异进行排序。

function sortByTwoFields(data, field1, field2) {
  data.sort(function (a, b) {
    // Work out difference of two fields and add them together to get the total
    var totalDifferenceA = Math.abs(field1.number - a[field1.field]) + Math.abs(field2.number - a[field2.field]);
    var totalDifferenceB = Math.abs(field1.number - b[field1.field]) + Math.abs(field2.number - b[field2.field]);
    
    // If a has a smaller total then b it should come first
    return totalDifferenceA - totalDifferenceB;
  });
}

const data = [
  {name: 'first', score: 22, average: 59},
  {name: 'second', score: 34, average: 83},
  {name: 'third', score: 40, average: 24},
  {name: 'fourth', score: 29, average: 49},
  {name: 'fifth', score: 23, average: 55}
];

sortByTwoFields(data, {field: 'score', number: 21}, {field: 'average', number: 50});
console.log(data);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接