自然排序,对象数组,多列,反向等

iLe*_*ing 2 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.
]
Run Code Online (Sandbox Code Playgroud)

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

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

我也在寻找一个优雅的解决方案.刚刚开始使用Ramdajs,它真是太棒了.我敢打赌,建立我需要使用的排序会更容易吗?我试过了,仍然无法做对.帮助不大?

UPD:

我找到了这个并将其与Ramda一起使用,如下所示:

fn = R.compose(R.sort(naturalSort), R.pluck("name"))
fn(arr)
Run Code Online (Sandbox Code Playgroud)

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

Ber*_*rgi 8

fn = R.compose(R.sort(naturalSort), R.pluck("name"))
Run Code Online (Sandbox Code Playgroud)

好像在起作用

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

sortBy不幸的是,我们不允许使用自定义比较函数(自然排序所需),并且在单个值中组合多个列可能是一致的,但是很麻烦.

我仍然不知道如何为多个领域做这件事

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

  • on(就像来自Haskell的那个),它采用a -> b转换和b -> b -> Number比较器函数在两个as 上产生一个比较器.我们可以像这样用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- 就像||,但数字不仅限于布尔人R.or.这可以用于将两个比较器链接在一起,如果第一个得到0(相等),则仅调用第二个比较器.或者,thenBy可以使用类似的库.但是我们自己来定义它:

    var or = R.curry(function(fst, snd, a, b) {
        return fst(a, b) || snd(a, b);
    });
    
  • negate - 反转比较的函数:

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

现在,配备这些我们只需要我们的比较函数(自然排序是你找到的那个的改编版本,另见排序数组元素(带数字的字符串),自然排序更多):

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;
}
Run Code Online (Sandbox Code Playgroud)

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

fn = R.sort(or(on(R.prop("name"), naturalCompare),
               on(R.prop("number_of_reqs"), negate(numberCompare))));
fn(arr)
Run Code Online (Sandbox Code Playgroud)