在JavaScript中如何像Python一样比较两个列表?

2 投票
5 回答
6888 浏览
提问于 2025-04-17 15:44

我刚接触JavaScript,但对Python比较熟悉。在Python中,我得到了这个输出:

In [1]: [1,9,[5,4,2]] > [1,9,[14,5,4]]
Out[1]: False

在JavaScript中:

> [1,9,[5,4,2]] > [1,9,[14,5,4]]
true

看起来数组在比较之前被转换成了字符串。

现在我想自己写一个函数,遍历数组并比较每个元素。我想出了这个CoffeeScript代码:

compare_list = (a, b)->
    if typeof a == "object" and typeof b != "object"
        return 1
    else if typeof a != "object" and typeof b == "object"
        return -1
    else if typeof a != "object" and typeof b != "object"
        if a > b
            return 1
        else if a < b
            return -1
        else
            return 0
    else if typeof a == "object" and typeof b == "object"
        for i in [0...a.length]
            if i > (b.length-1)
                return 1
            tmp = compare_list a[i], b[i]
            if tmp != 0
                return tmp
        if b.length > a.length
            return -1
        return 0

这个方法可以工作,但我觉得typeof a == "object"这一部分看起来不太对。有没有更简单、更好、更稳健的解决方案?

谢谢你的帮助。

5 个回答

1

我尝试实现一个JavaScript函数 compareArrays,它的功能类似于Python中的数组比较:

function compareArrays(a, b) {
    var aIsArray = Array.isArray(a),
        bIsArray = Array.isArray(b),
        cmp = 0;
    if (!aIsArray || !bIsArray) {
        throw new Error('Can\'t compare array to non-array: ' + a + ', ' + b);
    }

    _.find(a, function (aElem, index) {
        var bElem = b[index];
        if (Array.isArray(aElem) || Array.isArray(bElem)) {
            cmp = compareArrays(aElem, bElem);
        } else {
            cmp = (aElem > bElem) - (aElem < bElem);
        }

        if (cmp !== 0) {
            return true;
        }
    });

    return cmp;
}

这个函数使用了Underscore库来遍历数组,并且通过递归的方式来处理嵌套数组。

你可以查看我的示例,里面包含了一些基本的测试用例。

测试结果

[1,9,[5,4,2]] < [1,9,[14,5,4]]
[1,[1]] can't be compared to [1,1]
[1,[2]] > [1,[1]]
[2] > [1]
[1] == [1]
[] == []
4

这个算法基本上和之前的差不多,只是避免使用了 typeof 操作符,并在 for 循环中做了一点小技巧,这样就不用每次都检查数组的长度了:

cmp = (a, b) -> (a > b) - (a < b)

cmpArray = (a, b)->
  aIsArray = Array.isArray a
  bIsArray = Array.isArray b

  return cmp a, b if not aIsArray and not bIsArray
  return -1       if not aIsArray and     bIsArray
  return 1        if     aIsArray and not bIsArray

  # Both are arrays.
  len = Math.min a.length, b.length
  for i in [0...len] by 1
    if tmp = cmpArray a[i], b[i]
      return tmp
  a.length - b.length

可惜的是,CoffeeScript 不提供任何形式的模式匹配。如果有的话,这段代码会更简洁。你可以用 switch 语句来模拟一种简单的模式匹配,假如你想这样做的话:

cmpArray = (a, b)->
  switch "#{Array.isArray a},#{Array.isArray b}"
    when 'false,false' then (a > b) - (a < b) # Compare primitives.
    when 'false,true' then -1
    when 'true,false' then 1
    else
      len = Math.min a.length, b.length
      for i in [0...len] by 1
        if tmp = cmpArray a[i], b[i]
          return tmp
      a.length - b.length

不过,这样写在 CoffeeScript 中并不是特别符合习惯。如果 CoffeeScript 支持某种模式匹配,我肯定会选择这种写法,因为它看起来很简洁,只用了一行表达式,也不太依赖于提前返回的方式。

1

我也在尝试解决同样的问题,最后只想到了一种自定义的解决办法。你可以在这里查看:https://gist.github.com/ruxkor/2772234

因为在比较对象时,JavaScript会自动把字符串转换成其他类型,所以我觉得有必要使用一个自定义的比较函数,来模拟Python的比较方式。

撰写回答