40354
```

    sample = "私は<アイスクリーム|アイスキャンデー|アイス>が好き(なの)です。"
    
```

とします。

  1. `<>`に囲まれた部分は、どれでもいいが、線で区切られた単語のうち、この中のどれか一つは書かれていなければならないとします。
  2. `()`に囲まれた文字は、あってもなくても構わないとします。

このとき、1と2を満たす組み合わせとなる文を作りたいと思っています。  
まず、どれか3つのうちで3通り。`（）`はあるかないかで2通り。  
計6通りの文章が出来上がると思います。  
この6通りを瞬時に算出するプログラムを書きたいのですが、  
どうすればいいでしょうか。なんなら、`<>`などは別の記号に置き換えても  
もちろん問題ありません。  
  
環境: python3.6
CC BY-SA 3.0
2017-12-17T14:51:43.067
40343
2017-12-21T01:57:40.003
2017-12-21T01:57:40.003
24284
24284
question
python
文章の組み合わせを算出するプログラム
### 単語候補リストの作成

まずは、`< | >` や `( )`
といった記号を用いた独自の記法をパースして、文を構成する単語の候補になるリストたちを作成します。（パース部分に関しては、この回答では扱いません）

  * 必須:  
「`私は`」のように何にも囲まれていない出現が必須の単語。  
これは要素数1の単語候補リストになります。  
リスト表現: `["私は"]`

  * 選択:  
「`<アイスクリーム|アイスキャンデー|アイス>`」のように `< >` で囲まれた、どれかを選択する単語たち。  
これはそのまま、単語候補リストになります。  
リスト表現: `["アイスクリーム", "アイスキャンデー", "アイス"]`

  * 任意:  
「`(なの)`」のように `( )` で囲まれた、有っても無くてもよい単語。  
これは空文字とこの単語とを選択させる `<なの|>` と同義ですから、2要素の単語候補リストになります。  
リスト表現: `["なの", ""]`

  * 任意単語を含む選択:  
「`<>`の中にも`()`のあるパターン」というのは、たとえば `<(なの)|なのかも知れない>` のようなものだと思いますが、これは選択に空文字を含めた
`<なの||なのかも知れない>` と同義です。  
リスト表現: `["なの", "", "なのかも知れない"]`

これにより独自記法の、

```

    "私は<アイスクリーム|アイスキャンデー|アイス>が好き(なの)です。"
    
```

は5つのリスト、

```

    ["私は"],
    ["アイスクリーム", "アイスキャンデー", "アイス"],
    ["が好き"],
    ["なの", ""],
    ["です。"],
    
```

となります。

### 組み合わせ

目的はおそらく、単語候補リストのいわゆる「直積」を求めることです。  
「直積 アルゴリズム」などでWebを検索すると解説があると思いますが、以下では
[`itertools.product`](https://docs.python.jp/3/library/itertools.html#itertools.product)
をそのまま使っています。  
（`return` で返しているのは内包表記で生成したイテレータです。解り難ければループなどに展開して理解して下さい）

```

    #!/usr/bin/python3
    import itertools
    
    def gen_sentences(*word_lists):
        return ("".join(words) for words in itertools.product(*word_lists))
    
    
    if __name__ == "__main__":
        sentences = gen_sentences(
            ["私は"],
            ["アイスクリーム", "アイスキャンデー", "アイス"],
            ["が好き"],
            ["なの", ""],
            ["です。"],
        )
        for s in sentences:
            print(s)
    
```

出力:

```

    私はアイスクリームが好きなのです。
    私はアイスクリームが好きです。
    私はアイスキャンデーが好きなのです。
    私はアイスキャンデーが好きです。
    私はアイスが好きなのです。
    私はアイスが好きです。
    
```
CC BY-SA 3.0
2017-12-18T05:14:33.260
40354
2017-12-18T05:14:33.260
3054
40343
answer