94817


pythonで以下のようなリストを作成したいと考えています。

[code]

    [[i, 3+j] for i in range(3) for j in range(3)]
    #[[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]
    [[i, 3+j, 6+k] for i in range(3) for j in range(3) for k in range(3)]
    #[[0, 3, 6], [0, 3, 7], [0, 3, 8], [0, 4, 6], [0, 4, 7], [0, 4, 8], [0, 5, 6], 
    #[0, 5, 7], [0, 5, 8], [1, 3, 6], [1, 3, 7], [1, 3, 8], [1, 4, 6], [1, 4, 7], 
    #[1, 4, 8], [1, 5, 6], [1, 5, 7], [1, 5, 8], [2, 3, 6], [2, 3, 7], [2, 3, 8], 
    #[2, 4, 6], [2, 4, 7], [2, 4, 8], [2, 5, 6], [2, 5, 7], [2, 5, 8]]
    
[/code]

要素数4なら[[i, 3+j, 6+k, 9+l] for i in range(3) for j in range(3) for k in
range(3) for l in range(3)],...というようにしたいのですが、要素数を後から決めたいのです。  
要素数を引数にして任意の要素数からなるリストを作成する方法などありますでしょうか。  
解決の糸口をいただければと思います。

また、今後同様の問題にあたった場合、どのような検索をすればよいか教えていただけると助かります。


CC BY-SA 4.0
2023-05-11T07:36:10.423
94816
2023-05-15T06:11:14.320
58252
question
python python3
pythonで任意の要素数の組からなるリストを作りたい


以下のような感じでよいと思います。  
指定の要素数に見合った各要素の値の候補を用意して、それらをitertoolsのproductで全組み合わせ列挙します。

[code]

    from itertools import product
    
    N = 2
    a = [list(map(lambda v: v+i*3, range(3))) for i in range(N)]
    print(a) # [[0, 1, 2], [3, 4, 5]]
    
    ret = [p for p in product(*a)]
    print(ret) # [(0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]
    
[/code]

> また、今後同様の問題にあたった場合、どのような検索をすればよいか教えていただけると助かります。

まずは結果の生成ルール（仕様）を推測して決めます。  
そのさい、今回の問題では順列、組合せについての知識が必要かと思いました。  
あとはルールどおりの動作をするコードを書きます。  
コードを書いたあとで、それを簡単に実現できるパッケージがないか検索してもよいでしょう。


CC BY-SA 4.0
2023-05-11T07:55:11.050
94817
2023-05-11T07:55:11.050
25830
94816
answer


NumPy での場合 (すべて NumPyというわけではないが)

[code]

    from itertools import product
    import numpy as np
    
    N = 3
    p = np.split(np.arange(3 *N), N)
    list(product(*p))
    #[(0, 3, 6),
    # (0, 3, 7),
    # (0, 3, 8),
    # (0, 4, 6),
    # (0, 4, 7),
    # (0, 4, 8),
    # 以下続く
    
[/code]

* * *

`itertools.product` 相当も NumPyで行う場合

[code]

    import numpy as np
    
    def fn(num):
        return np.stack(np.meshgrid(
            *np.split(np.arange(3 *num), num)), -1).reshape(-1, num)
    
    fn(3)
    
    # array([[0, 3, 6],
    #        [0, 3, 7],
    #        [0, 3, 8],
    #        [1, 3, 6],
    #        [1, 3, 7],
    #        [1, 3, 8],
    #        [2, 3, 6],
    #(略)
    
[/code]

参考: <https://stackoverflow.com/questions/1208118/using-numpy-to-build-an-
array-of-all-combinations-of-two-arrays>


CC BY-SA 4.0
2023-05-11T08:28:13.207
94818
2023-05-15T06:11:14.320
2023-05-15T06:11:14.320
43025
43025
94816
answer


[More Itertools](https://more-itertools.readthedocs.io/en/stable/) の
[chunked](https://more-
itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked) を使う場合。

[code]

    from itertools import product
    from more_itertools import chunked
    from pprint import pprint
    
    def cartesian_product(n):
        return [*product(*chunked(range(3*n), 3))]
    
    if __name__ == '__main__':
        for i in (2, 3):
            print(f'n = {i}')
            pprint(cartesian_product(i), compact=True)
    
    # n = 2
    # [(0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]
    # n = 3
    # [(0, 3, 6), (0, 3, 7), (0, 3, 8), (0, 4, 6), (0, 4, 7), (0, 4, 8), (0, 5, 6),
    #  (0, 5, 7), (0, 5, 8), (1, 3, 6), (1, 3, 7), (1, 3, 8), (1, 4, 6), (1, 4, 7),
    #  (1, 4, 8), (1, 5, 6), (1, 5, 7), (1, 5, 8), (2, 3, 6), (2, 3, 7), (2, 3, 8),
    #  (2, 4, 6), (2, 4, 7), (2, 4, 8), (2, 5, 6), (2, 5, 7), (2, 5, 8)]
    
[/code]


CC BY-SA 4.0
2023-05-11T09:23:52.547
94819
2023-05-11T09:29:04.477
2023-05-11T09:29:04.477
47127
47127
94816
answer


<https://docs.python.org/ja/3/library/itertools.html#itertools.product>  
`itertools.product`のrepeat引数がまさにそのための機能だと思います。

[code]

    from itertools import product
    
    for x in product(range(3), repeat=4):
        print(x)
    
[/code]

でまず様子を見ると

[code]

    (0, 0, 0, 0)
    (0, 0, 0, 1)
    (0, 0, 0, 2)
    (0, 0, 1, 0)
    (0, 0, 1, 1)
    (0, 0, 1, 2)
    (0, 0, 2, 0)
    (0, 0, 2, 1)
    (0, 0, 2, 2)
    (0, 1, 0, 0)
    (0, 1, 0, 1)
    (0, 1, 0, 2)
    (0, 1, 1, 0)
    (0, 1, 1, 1)
    以下略
    
[/code]

と出てくるので、2や3も試して、欲しいものだなと判断します。

i, j, k, l,,, → i, 3+j, 6+k, 9+l,,, は割と素直に内包表記で書けて、

[code]

    N = 4
    [[i * 3 + n for i, n in enumerate(x)] for x in product(range(3), repeat=N)]
    
[/code]

とできます。  
i, 3+j, 6+k, 9+l,,, が 0×3+i, 1×3+j, 2×3+k, 3×3+l,,, に見えるかどうかは数学の能力かなと思いました。

* * *

検索で届く範囲ではないと感じました。  
私は「これはitertoolsに必要なものがあるだろう」という直感しました。  
Pythonの標準ライブラリの範囲は一通り目を通しておくのがいいのではないでしょうか。


CC BY-SA 4.0
2023-05-11T11:09:48.990
94820
2023-05-11T11:09:48.990
12274
94816
answer