2

我对 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

似乎在比较之前将数组转换为字符串。

现在我想自己编写一个函数并遍历数组并比较每个元素。我想出了这个咖啡脚本代码:

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"对我来说这部分看起来不正确。是否有更简单/更好/更强大的解决方案?

谢谢你的帮助。

4

5 回答 5

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 支持某种模式匹配,我肯定会选择这种解决方案,因为我认为它只是一个表达式,而不是(过多)依赖于早期返回,读起来非常好。

于 2013-02-13T13:27:36.957 回答
1

试图解决同样的问题,我也只是想出了一个自定义的解决方案。https://gist.github.com/ruxkor/2772234

由于Javascript在比较对象时使用字符串强制,我认为有必要使用自定义比较函数来模拟Python行为。

于 2013-02-13T12:12:59.760 回答
1

让我们让它变得简约:

function compare(a, b) {
    if (a instanceof Array && b instanceof Array) {
        for (var r, i=0, l=Math.min(a.length, b.length); i<l; i++)
            if (r = compare(a[i], b[i]))
                return r;
        return a.length - b.length;
    } else // use native comparison algorithm, including ToPrimitive conversion
        return (a > b) - (a < b);
}

instanceof用于阵列检测,请参阅本文讨论)

如果要使对象始终大于基元,可以将最后一行更改为

        return (typeof a==="object")-(typeof b==="object") || (a>b)-(a<b);
于 2013-02-13T13:24:11.320 回答
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;
}

它使用下划线遍历数组,并递归处理嵌套数组。

请参阅我的小提琴,其中包括一个原始测试套件。

测试结果

[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]
[] == []
于 2013-02-13T13:37:54.077 回答
0

这很丑陋,但这似乎可以完成工作:

var compareLists = function compare(listA, listB) {
    if (Array.isArray(listA)) {
        if (Array.isArray(listB)) {
            if (listA.length == 0) {
                if (listB.length == 0) {
                    return 0;
                } else {
                    return -1;
                }
            } else {
                if (listB.length == 0) {
                    return +1;
                } else {
                    return compare(listA[0], listB[0]) || 
                           compare(listA.slice(1), listB.slice(1));
                }
            }
        } else {
            return -1; // arbitrary decision: arrays are smaller than scalars
        }
    } else {
        if (Array.isArray(listB)) {
            return +1; // arbitrary decision: scalars are larger than arrays
        } else {
            return listA < listB ?  -1 : listA > listB ? + 1 : 0;
        }
    }
};

compareLists([1, 9, [5, 4, 2]], [1, 9, [14, 5, 4]]); // -1
compareLists([1, 9, [5, 4, 2]], [1, 9, [5, 4]]);     // +1
compareLists([1, 9, [5, 4, 2]], [1, 9, [5, 4, 2]]);  //  0

根据您的环境,您可能需要填充Array.isArray

if (!Array.isArray) {
    Array.isArray = function (obj) {
        return Object.prototype.toString.call(obj) === "[object Array]";
    };
}
于 2013-02-13T12:53:16.723 回答