70826


長さが2万を超えるリストがあります．  
そのリストから8個ずつ(Keyが1番目の要素，残りの7つがValue)に分けてDictへと変換したいです．（そのリストは8で割り切れます）  
具体的な例を出すと，リスト

[code]

    A = [1, 3, 5, 2, 4, 6, 7, 9, 11, 8, 10, 12, 13, 14, 15, 27]
    
[/code]

のようなリストに対して，期待する出力は

> tmp_dict = {1: [3, 5, 2, 4, 6, 7, 9], 11: [8, 10, 12, 13, 14, 15, 27]}

のようになります．要するに８の倍数の値をKey，それ以外の7つをValueに変換するといった内容になります．  
どなたかご教授お願いします．  
[追記]Keyが重複する可能性があります．重複した場合はそのKeyとValueは無視して元のKeyとValueのままにするような仕様にしたいです．


CC BY-SA 4.0
2020-09-29T14:31:28.587
70819
2020-09-30T10:50:36.687
2020-09-30T01:03:15.970
36750
36750
question
python python3
リストから特定の長さのDictへの変換方法


スライスして辞書化する例です。

[code]

    A = [ 1,  3,  5,  2,  4,  6,  7,  9,
         11,  8, 10, 12, 13, 14, 15, 27,
         11, 22, 33, 44, 55, 66, 77, 88]
    
    group_length = 8
    dict = {}
    for i in range(int(len(A) / group_length)):
        start = i * group_length
        end = (i + 1) * group_length
        key = A[start]
        # 既にキーが存在する場合はスキップ
        if key in dict:
            continue
        dict[key] = A[start + 1: end]
    
    print(dict)
    # {1: [3, 5, 2, 4, 6, 7, 9], 11: [8, 10, 12, 13, 14, 15, 27]}
    
[/code]


CC BY-SA 4.0
2020-09-30T01:41:21.533
70826
2020-09-30T01:41:21.533
9820
70819
answer


## 重複した場合は元の Key : Value 優先タイプ

[code]

    A = [1, 3, 5, 2, 4, 6, 7, 9, 11, 8, 10, 12, 13, 14, 15, 27, 11, 28, 30, 32, 33, 34, 35, 47]
    sz = 8
    lsk = [A[i] for i in range(0, len(A), sz)]
    # lst = [A[i:i+sz] for i in range(0, len(A), sz)]
    # tmp_dict = {lst[i][0]:lst[i][1:] for i in range(0, len(lst)) if lst[i][0] not in lsk[:i] }
    tmp_dict = {A[i]:A[i+1:i+sz] for i in range(0, len(A), sz) if A[i] not in lsk[:i//sz] }
    print(tmp_dict)  # {1: [3, 5, 2, 4, 6, 7, 9], 11: [8, 10, 12, 13, 14, 15, 27]}
    
[/code]

## 重複した場合は後の Key : Value で上書きするタイプ

[code]

    A = [1, 3, 5, 2, 4, 6, 7, 9, 11, 8, 10, 12, 13, 14, 15, 27, 11, 28, 30, 32, 33, 34, 35, 47]
    sz = 8
    tmp_dict = {A[i]:A[i+1:i+sz] for i in range(0, len(A), sz)}
    print(tmp_dict)  # 上書き {1: [3, 5, 2, 4, 6, 7, 9], 11: [28, 30, 32, 33, 34, 35, 47]}
    
[/code]

## 重複した場合は Value を連結するタイプ

[code]

    def list_to_dict(lst, sz):
        from collections import defaultdict
        lst = [lst[i:i+sz] for i in range(0, len(lst), sz)]
        dic = defaultdict(list)
        for ls in lst:
            dic[ls[0]] += ls[1:]
        return dict(dic)
    
    A = [1, 3, 5, 2, 4, 6, 7, 9, 11, 8, 10, 12, 13, 14, 15, 27, 11, 28, 30, 32, 33, 34, 35, 47]
    tmp_dict = list_to_dict(A, 8)
    print(tmp_dict)   # 連結 {1: [3, 5, 2, 4, 6, 7, 9], 11: [8, 10, 12, 13, 14, 15, 27, 28, 30, 32, 33, 34, 35, 47]}
    
[/code]

lst = [lst[i:i+sz] for i in range(0, len(lst), sz)]  
は  
lst = list(map(list, list(zip(*[iter(A)]*sz))))  
と性能比較した方が良いかもしれません。


CC BY-SA 4.0
2020-09-30T05:51:01.977
70830
2020-09-30T09:13:20.007
2020-09-30T09:13:20.007
41756
41756
70819
answer


[more-itertools: More routines for operating on iterables, beyond
itertools](https://github.com/more-itertools/more-itertools)
に、[unique_everseen](https://more-
itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_everseen)
というメソッドがあります。

> **more_itertools.unique_everseen(iterable, key=None)**
>
> Yield unique elements, preserving order.

これと、[numpy.array_split()](https://numpy.org/doc/stable/reference/generated/numpy.array_split.html#numpy.array_split)
を使う方法です。

[code]

    from more_itertools import unique_everseen
    from numpy import array_split
    
    A = [
       1,  3,  5,  2,  4,  6,  7,  9,
      11,  8, 10, 12, 13, 14, 15, 27,
       1, 25, 22, 30, 32, 35, 37, 42,
    ]
    
    tmp_dict = {
      lst[0]: lst[1:].tolist()
      for lst in
      unique_everseen(array_split(A, len(A)//8), key=lambda x: x[0])
    }
    
    print(tmp_dict)
    =>
    {1: [3, 5, 2, 4, 6, 7, 9], 11: [8, 10, 12, 13, 14, 15, 27]}
    
[/code]


CC BY-SA 4.0
2020-09-30T10:50:36.687
70841
2020-09-30T10:50:36.687
70819
answer