javascript - 自然排序、对象数组、多列、反向等

标签 javascript sorting underscore.js lodash ramda.js

我迫切需要通过我们的 tastypie api 实现模拟排序的客户端排序,它可以获取多个字段并返回排序后的数据。因此,例如,如果我有这样的数据:

arr = [ 
  { name: 'Foo LLC',        budget: 3500,  number_of_reqs: 1040 }, 
  { name: '22nd Amendment', budget: 1500,  number_of_reqs: 2000 },
  { name: 'STS 10',         budget: 50000, number_of_reqs: 500  },
  ...
  etc.
]

和给定的列进行排序,例如:['name', '-number_of_reqs'] 它应该按 name(升序)和 number_of_reqs(降序)。我无法理解这个, 首先,它必须是“自然排序”,如果我们谈论对单个列进行排序,它应该很容易获得,但我需要能够对多个列进行排序。

我也不确定为什么我在使用 lodash 的 _.sortBy 时会得到不同的结果(从 api 的方式)? _.sortBy 不是“自然的”还是我们的 api 坏了?

我也在寻找一个优雅的解决方案。最近才开始使用 Ramdajs ,真是太棒了。我敢打赌,使用它来构建我需要的排序会更容易吗?我已经尝试过了,仍然无法正确处理。帮助不大?

更新:

我找到了 this并像这样与 Ramda 一起使用它:

fn = R.compose(R.sort(naturalSort), R.pluck("name"))
fn(arr)

似乎适用于平面数组,但我仍然需要找到一种方法将它应用于数组中的多个字段

最佳答案

fn = R.compose(R.sort(naturalSort), R.pluck("name"))

seems to be working

真的吗?我希望返回一个排序的名称数组,而不是按名称属性对对象数组进行排序。

不幸的是,使用 sortBy 不允许我们提供自定义比较函数(自然排序需要),并且将多个列组合成一个值以进行一致比较可能是可行的,但很麻烦。

I still don't know how to do it for multiple fields

函数式编程在这里可以做很多事情,不幸的是 Ramda 并没有真正为比较器配备有用的函数(R.comparator 除外)。我们需要三个额外的助手:

  • on(如 one from Haskell ),采用 a -> b 转换和 b -> b -> Number 比较器函数在两个 a 上产生一个比较器。我们可以像这样用 Ramda 创建它:

    var on = R.curry(function(map, cmp) {
        return R.useWith(cmp, map, map);
        return R.useWith(cmp, [map, map]); // since Ramda >0.18 
    });
    
  • or - just like ||, but on numbers not limited to booleans like R.or. This can be used to chain two comparators together, with the second only being invoked if the first yields 0 (equality). Alternatively, a library like thenBy could be used for this. But let's define it ourselves:

    var or = R.curry(function(fst, snd, a, b) {
        return fst(a, b) || snd(a, b);
    });
    
  • negate - a function that inverses a comparison:

    function negate(cmp) {
        return R.compose(R.multiply(-1), cmp);
    }
    

Now, equipped with these we only need our comparison functions (that natural sort is an adapted version of the one you found, see also Sort Array Elements (string with numbers), natural sort for more):

var NUMBER_GROUPS = /(-?\d*\.?\d+)/g;
function naturalCompare(a, b) {
    var aa = String(a).split(NUMBER_GROUPS),
        bb = String(b).split(NUMBER_GROUPS),
        min = Math.min(aa.length, bb.length);

    for (var i = 0; i < min; i++) {
        var x = aa[i].toLowerCase(),
            y = bb[i].toLowerCase();
        if (x < y) return -1;
        if (x > y) return 1;
        i++;
        if (i >= min) break;
        var z = parseFloat(aa[i]) - parseFloat(bb[i]);
        if (z != 0) return z;
    }
    return aa.length - bb.length;
}
function stringCompare(a, b) {
    a = String(a); b = String(b);
    return +(a>b)||-(a<b);
}
function numberCompare(a, b) {
    return a-b;
}

现在我们可以准确地对您想要的对象进行比较:

fn = R.sort(or(on(R.prop("name"), naturalCompare),
               on(R.prop("number_of_reqs"), negate(numberCompare))));
fn(arr)

关于javascript - 自然排序、对象数组、多列、反向等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26323317/

相关文章:

performance - 为什么 Haskell 使用归并排序而不是快速排序?

javascript - Underscore.js _.where 方法的意外结果

javascript - 使用 ColdFusion 和 Microsoft SQL 删除特殊字符的最佳方法?

javascript - 在 amchart 中以像素为单位设置 Y 值

javascript - 基于嵌套对象数组的过滤

javascript - 在 Underscore.js 中合并两个相同的对象

javascript - 根据在数组中查找具有另一个值的对象来返回某个对象的值

Javascript: "if"条件内的三元运算符

java - 插入和删除最大堆java

algorithm - Dart:总结 map 列表中各项的正确方法是什么?