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 はいかなる種類のパターン マッチングも提供しません。これにより、このコードはより DRY-er になります。必要に応じて、ステートメントを使用して貧しい人のパターン マッチングを偽造でき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

ミニマルにしましょう:

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

同じ問題を解決しようとして、私もカスタムソリューションを思いついただけです。https://gist.github.com/ruxkor/2772234

Javascriptはオブジェクトを比較するときに文字列強制を使用しているため、Pythonの動作をシミュレートするにはカスタム比較関数を使用する必要があると思います。

于 2013-02-13T12:12:59.760 に答える
1

compareArraysPython で配列比較のように動作する JavaScript 関数を実装してみました。

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

環境によっては、次のように shim することをお勧めしますArray.isArray

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