2012-03-20 18 views
42

最近私は、リストを変換するときに、順序や要素が変更され、文字でソートされていることに気付きました。 要素の順序を変更しますか?

は、この例を考えてみましょう:

x=[1,2,20,6,210] 
print x 
# [1, 2, 20, 6, 210] # the order is same as initial order 

set(x) 
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted 

私の質問です -

  1. ですが、なぜでしょうか?
  2. 初期設定を失うことなく設定操作(特に差異設定)を行うにはどうすればよいですか?
+5

特に、設定操作を行っている場合は、最初の順序を失いたくないのはなぜですか? 「オーダー」は、Pythonだけでなく数学でも、セットに意味のない概念です。 –

+46

@KarlKnechtel - はい "注文は数学ではセットに意味のない概念です"しかし、現実世界の問題があります。 –

答えて

50
  1. setは順序付けられていないデータ構造です。

  2. setを使用するのではなく、collections.OrderedDictないでください:

    >>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210]) 
    >>> b = collections.OrderedDict.fromkeys([6, 20, 1]) 
    >>> collections.OrderedDict.fromkeys(x for x in a if x not in b) 
    OrderedDict([(2, None), (210, None)]) 
    

    注意(それは任意の反復可能なことができるようbの順序は、重要ではありませんが、それはOをサポートする反復可能でなければならないこと1)メンバーシップテスト。

編集:上記の答えはあなたがまた元集合演算の結果に、特に、すべての発生コレクション上(注文)セット操作を実行できるようにすることを想定しています。これが必要でない場合は、コレクションの一部にリストを使用するだけで、他のコレクションには単純にリストを使用できます。

>>> a = [1, 2, 20, 6, 210] 
>>> b = set([6, 20, 1]) 
>>> [x for x in a if x not in b] 
[2, 210] 

これはbの順序を失い、高速のメンバーシップのaのテストとその結果を許可していません。セットは高速メンバーシップテストを可能にし、リストはオーダーを保持します。これらの機能が両方とも同じコレクションに必要な場合は、collections.OrderedDictを使用してください。

+0

なしオブジェクトのコストは16バイトです。デフォルトのOrderedSet()のみが存在する場合。 : – Sean

13

あなたの最初の質問に答えて、setは集合演算に最適化されたデータ構造であり、数学的集合のように、要素の特定の順序を強制/維持しません。 setの抽象概念は順序を強制しないので、実装は行いません。リストからセットを作成すると、Pythonはセットに対して効率的にセット操作を実行できる内部実装のニーズに応じて、エレメントの順序を変更する自由をとります。

3

他の回答に示すように、セットは要素の順序を保持していないデータ構造(および数学的概念)です -

しかし、集合および辞書の組み合わせを使用することによって、あなたがwatheverを達成できることも可能ですあなたが欲しい - これらのスニペットを使用してみてください:

# save the element order in a dict: 
x_dict = dict(x,y for y, x in enumerate(my_list)) 
x_set = set(my_list) 
#perform desired set operations 
... 
#retrieve ordered list from the set: 
new_list = [None] * len(new_set) 
for element in new_set: 
    new_list[x_dict[element]] = element 
1

ので、私はあなたが望むものを達成プラス私は辞書に複数の項目を追加できるように助けたように建物のスヴェンの答えに、私はcollections.OrderedDictを使用した:

import collections 

x=[1,2,20,6,210] 
z=collections.OrderedDict.fromkeys(x) 
z 
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)]) 

あなたはアイテムを追加するが、それでもあなただけ行うことができますセットのようにそれを扱いたい場合:

z['nextitem']=None 

そして、あなたは、zのような操作を行うことができます。辞書のキー()とのセットを取得:ここ

z.keys() 
[1, 2, 20, 6, 210] 
+0

リスト出力を取得するには 'list(z.keys())'を実行する必要があります。 – jxn

+0

、Python 3ではyes、Python 2では指定してはいけません – jimh

-5

はそれを行うための簡単な方法です:Pythonの3.6で

x=[1,2,20,6,210] 
print sorted(set(x)) 
+2

これは順序を必ずしも保持しません。 –

+1

入力がソートされている場合にのみ、この回答が正しい – msudder

10

set()秩序を維持する必要がありますが、別の存在でありますPython 2と3のソリューション:

>>> x = [1, 2, 20, 6, 210] 
>>> sorted(set(x), key=x.index) 
[1, 2, 20, 6, 210] 
+8

注文保全に関する2つの注意点:Python 3.6以降であっても、実装の詳細と見なされるため、依存しないでください。 'x.index'が呼び出されるたびに線形検索が行われるので、非効率的です。二次的な複雑さで問題がなければ、最初に' set'を使う理由はありません。 –

+9

@ThijsvanDienこれは間違っています。 set() 'はPython 3.6では整理されていません。実装の詳細ではなく、' dict'を考えています –

+0

@Chris_Rands私は修正されています。 rder。いずれにせよ、実装の詳細。 –

関連する問題