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

时间:2018-07-25 12:44:57

标签: javascript sorting lodash

我想按两个字段对数组进行排序,同时提供所需的数字对其进行排序。我尝试使用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}
];

任何想法将不胜感激

4 个答案:

答案 0 :(得分:1)

仅使用_.sortBy中的lodash怎么样?

_.sortBy(data, [a=> Math.abs(a.score - 21), a=> Math.abs(a.average - 50)])

这还不够吗?

编辑

是的,是的!如果您需要从一个位置进行排序(执行)并且仅(恰好有2个)2个嵌套字段,则可以使用此ole衬套,但是如果您从多个位置进行调用并且具有最接近值的diff字段(嵌套),则您可以将其包装在函数中,动态地准备itarees并将其传递给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});

答案 1 :(得分: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;
    });
}

答案 2 :(得分: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);

答案 3 :(得分:0)

通过按任意数量的字段(而不只是两个)进行排序,可以很容易地使它通用:

fname:"/tmp/table1.csv"
tname: "table1"
/ how do I save table tname to file fname?