2016-04-28 5 views
1

皆さん。私は最近Python 2から3.5.1に切り替わり、書き直すことができないアサーション関数がありました。一般的に注文なしでdictsで2つのリストをアサートする方法はありますか?

def assertEqualUnordered(self, data1, data2): 
    """ 
    compare that data are similar 
    i.e.: 
    [d1, d2] == [d2, d1] 
    or 
    {'a': [d1, d2]} == {'a': [d2, d1]} 
    or 
    [{'a': [d1, d2]}, {'b': [d3, d4]}] == [{'b': [d4, d3]}, {'a': [d2, d1]}] 
    """ 
    if isinstance(data1, list) or isinstance(data1, tuple): 
     self.assertEqual(len(data1), len(data2)) 
     for d1, d2 in zip(sorted(data1), sorted(data2)): 
      self.assertEqualUnordered(d1, d2) 
    elif isinstance(data1, dict): 
     data1_keys = sorted(data1.keys()) 
     data2_keys = sorted(data2.keys()) 
     self.assertListEqual(data1_keys, data2_keys) 
     for key in data1_keys: 
      self.assertEqualUnordered(data1[key], data2[key]) 
    else: 
     self.assertEqual(data1, data2) 

このコードは、正常に動作しますが、私が持っているよりも、D1およびD2は、dictsある場合:

TypeError: unorderable types: dict() < dict()

は、どのように私はpy3kで動作するように書き直すことができますか?

EDIT 1: 簡素化コードの例:

def assertEqualUnordered(data1, data2): 
    assert len(data1) == len(data2) 
    for d1, d2 in zip(sorted(data1), sorted(data2)): 
     assert d1 == d2 

data1 = [{'a': 'a'}, {'b': 'b'}] 
data2 = [{'b': 'b'}, {'a': 'a'}] 
assertEqualUnordered(data1, data2) 
+0

あなたが見ている障害をより詳しく調べるためにこれを簡略化できますか?これはリストの代わりにビューを返すkeys()と関係があると仮定します。 https://docs.python.org/3.0/whatsnew/3.0.html また、完全なスタックトレースを含めることはできますか? – jgritty

+0

例外をスローするコードを表示します。このコードでは、どこでも '<'は使用されません。 –

+0

@jgrittyコード例 – vanadium23

答えて

3

私は、これはそれを行うための最も簡単な方法であるかどうかわからないんだけど、あなたはPythonのcmp機能を復活させることにより、ソート作業を作ることができます3を除去した。これらの線に沿って何か:

def cmp(lhs, rhs): 
    try: 
     if lhs == rhs: 
      return 0 
     elif lhs < rhs: 
      return -1 
     else: 
      return 1 
    except TypeError: 
     if isinstance(lhs, dict) and isinstance(rhs, dict): 
      return dict_cmp(lhs, rhs) 
     raise 

dict_cmpの実現のためには、あなたがあなたのcmp機能を持っていたら、あなたはsorted(data1, key = functools.cmp_to_key(cmp))を行うことができますIs there a description of how __cmp__ works for dict objects in Python 2?

を参照してください。

これは完全型ではありません。複合型の比較をカバーすることはできませんでした。例えば、オブジェクトの1つとして[{'a' : 'b'}, ['a']]を渡した場合などです。しかし、うまくいけば、私は入って行く方向を提供したのです。

代替案は、O(n^2)アルゴリズムにフォールバックすることです。これは、辞書には命令がないというPython3の意見に実質的に同意します。リストをソートしてそれらを比較するのではなく、左の各アイテムを順番に取得し、それと等しい右のアイテムを検索します(削除して両方のアイテムが同じであることを確認します。 [x, x, y]が​​に等しいと誤って主張することは望ましくありません。

Btw、答えには本当に必要ではありませんが、あなたの現在のコードでは['a', 'b']は、{'a' : 'foo', 'b' : 'bar'}と等しいですが、リストが左側にあり、右側が辞書にある場合に限ります。あなたが他の方法でそれらを渡した場合、コードがkeys()をリスト上で呼び出そうとすると例外が発生します。これは、あなたが通過しようとしているものに応じてアドレッシングを必要とするかもしれません;-)

関連する問題