

まず以下のような辞書型があったとします。

[code]

    xdic={sub1:{(0,A),(1,C),(0,B),(1,D)}, sub2:{(0,A),(2,C),(1,B),(3,D)}}
    
[/code]

これを(key毎に)値の第一引数で分け、key名を先頭にしたリストにまとめる方法が分かりません。

つまり

key:sub1について  
0を引数にまとめる:`(sub1,A,B)`  
1を引数にまとめる:`(sub1,C,D)`

key:sub2について  
0を引数にまとめる:`(sub2,A)`  
1を引数にまとめる:`(sub2,B)`  
2を引数にまとめる:`(sub2,C)`  
3を引数にまとめる:`(sub2,D)`

この様なアウトプットを求めています。

環境はpython2.7です。分かる方何卒宜しくお願いいたします。


CC BY-SA 3.0
2016-09-14T19:00:36.310
28889
2016-10-05T07:50:08.967
2016-09-15T02:19:51.097
2521
18779
question
python
tuple を要素に持つ set を、各 tuple の第一引数で分けてリストにまとめる方法


素直にループで回す例です。

[code]

    #!/usr/bin/python2
    #coding: utf-8
    from __future__ import print_function
    
    xdic = {
            'sub1': {(0, 'A'), (0, 'B'), (1, 'C'), (1, 'D')},
            'sub2': {(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D')},
            }
    
    
    def dic_per_first_item(pre, collection):
        result = {}
        for v in collection:
            first_item = v[0]
            if first_item not in result:
                result[first_item] = [pre]
    
            # 値のタブルが2要素と決っているなら、以下のループは必要ないです
            # result[first_item].append(v[1]) のような形でよいです
            rest_items = v[1:]
            for i in rest_items:
                result[first_item].append(i)
    
        return result
    
    
    for key, value in xdic.items():
        print("about:", key)
        for k, v in dic_per_first_item(key, value).items():
            print(k, ":", v)
    
[/code]

出力:

[code]

    about: sub2
    0 : ['sub2', 'A']
    1 : ['sub2', 'B']
    2 : ['sub2', 'C']
    3 : ['sub2', 'D']
    about: sub1
    0 : ['sub1', 'B', 'A']
    1 : ['sub1', 'C', 'D']
    
[/code]

* * *

少し質問を編集で直しておこうかと思った点があるのですが、タイミングにより、他の方の回答と齟齬が出るかも知れないので止めました。  
以下がそれです。

> 辞書型の値がリストで与えられてる

とされていますが、この（`xdic`に代入されている）辞書の値は`[ ]`でなく`{
}`で囲まれていますので、リストではなく[set（集合）](http://docs.python.jp/2.7/library/stdtypes.html#set-
set-frozenset)になっています。  
今回の目的に沿っていればそれで構いませんが、順序が無かったりしますので気を付けて下さい。  
回答のアウトプットを見ると分かりますが、順序は不定です。

> リストにまとめる

結果の形として、`(sub1,A,B)`を示されていますが、これも`[ ]`でなく`( )`で囲まれていますので、リストにはならず、タブルになります。  
（これはPythonの値の表現ではなく疑似コードとして示されたのかもしれませんが。）  
回答ではリストに変更しました。

> 値の第一引数

という言葉ですが、これは関数に渡すものを指すのに使われます（[引数](https://ja.wikipedia.org/wiki/%E5%BC%95%E6%95%B0)）。  
リストなどの中身の要素を指す場合は、そのまま「リストの要素」とするとよいです。  
「第一引数」ではなく、「最初の要素」などと呼びます。

>
[code]

>     xdic={sub1:{(0,A),(1,C),(0,B),(1,D)}, sub2:{(0,A),(2,C),(1,B),(3,D)}}
>  
[/code]

の中にある、`sub1`、`sub2l`、`A`、などといった変数はプログラムの中で、適切な値を設定されていることと思いますが、コードの断片を示す場合は、可能な限り独立して動くコードにすると伝わり易いです。  
今回の場合、全て定数（文字列）にしても質問の本旨に影響ないと思います。  
回答では文字列にしました。

* * *

追記:  
他の方が一部直して下さいましたね。  
上記は最初のバージョンに関してのコメント、という事でお願いします。


CC BY-SA 3.0
2016-09-15T02:27:28.870
28893
2016-09-15T02:37:02.073
2016-09-15T02:37:02.073
3054
3054
28889
answer

[code]

    xdic={'sub1': {(0, 'A'),(1, 'C'),(0, 'B'),(1, 'D')},
          'sub2': {(0, 'A'),(2, 'C'),(1, 'B'),(3, 'D')},}
    
[/code]

setと内包表記を使ってシンプルに書く。

Python2

[code]

    for key, value in xdic.items():     
        print '\nkey:%sについて' % (key,)
        for first in {f for f, _ in value}:
            print '%s: %s' % (first, [key] + [s for f, s in value if f==first],)
    
[/code]

Python3

[code]

    for key, value in xdic.items():
        print('\nkey:{}について'.format(key))
        for first in {f for f, _ in value}:
            print('{}:{}'.format(first, [key] + [s for f, s in value if f==first]))
    
[/code]

出力：

[code]

    key:sub2について
    0: ('sub2', 'A')
    1: ('sub2', 'B')
    2: ('sub2', 'C')
    3: ('sub2', 'D')
    
    key:sub1について
    0: ('sub1', 'B', 'A')
    1: ('sub1', 'C', 'D')
    
[/code]

`{f for f, _ in
value}`でsetにすることでタプルの最初の要素について重複のないリストを生成し、各値に対応するタプルの２番目の要素のリストを生成する。print文による書き出しだけが目的であれば上記のように書く。

リストにまとめるのであれば、以下のようにdictにまとめる。

[code]

    result = {}
    for key, value in xdic.items():
        result[key] = {}
        for first in {f for f, _ in value}:
            result[key][first] = [s for f, s in value if f==first]
    
[/code]

出力：

[code]

    {'sub1': {0: ['A', 'B'], 1: ['D', 'C']},
     'sub2': {0: ['A'], 1: ['B'], 2: ['C'], 3: ['D']}}
    
[/code]


CC BY-SA 3.0
2016-09-24T07:06:11.150
29087
2016-10-05T04:21:35.120
2016-10-05T04:21:35.120
18902
18902
28889
answer


## PyFunctionalを使う

[code]

    from pprint import pprint
    from functional import seq
    
    xdic={'sub1': {(0, 'A'),(1, 'C'),(0, 'B'),(1, 'D')},
          'sub2': {(0, 'A'),(2, 'C'),(1, 'B'),(3, 'D')},}
    
    pprint(
        seq(xdic.items())
        .sorted()
        .map(lambda (k, v): (k, seq(v)))
        .map(lambda (k, v): (v.group_by_key().map(lambda e: sorted(e[1])), k))
        .map(lambda (v, k): v.map(lambda e: [k] + e))
    )
    
[/code]

## 結果

[code]

    [[['sub1', 'A', 'B'], ['sub1', 'C', 'D']],
     [['sub2', 'A'], ['sub2', 'B'], ['sub2', 'C'], ['sub2', 'D']]]
    
[/code]

## 標準の関数だけ使う

メソッドチェーンができないので可読性が著しく悪いですが、こんな感じです。

[code]

    from pprint import pprint
    from itertools import groupby
    
    xdic={'sub1': {(0, 'A'),(1, 'C'),(0, 'B'),(1, 'D')},
          'sub2': {(0, 'A'),(2, 'C'),(1, 'B'),(3, 'D')},}
    
    pprint(map(lambda key: map(lambda (key, l): l.insert(0, key) or l,
                               sorted(
                                   map(lambda x: (key, map(lambda y: y[1], sorted(x[1]))),
                                       groupby(xdic[key], key=lambda x:x[0])))
                               ), sorted(xdic)))
    
[/code]

### 結果

[code]

    [[['sub1', 'A', 'B'], ['sub1', 'C', 'D']],
     [['sub2', 'A'], ['sub2', 'B'], ['sub2', 'C'], ['sub2', 'D']]]
    
[/code]

### 敢えてこのように書く意義は？

Map-ReduceやSparkなどではリストの変形操作を関数型っぽい書き方で延々とやります。実際PySparkで書いたらよく似たコードになるでしょう。


CC BY-SA 3.0
2016-10-05T05:34:19.603
29367
2016-10-05T07:50:08.967
2016-10-05T07:50:08.967
7837
7837
28889
answer