🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

460閲覧

条件を満たすリストの作成の効率化について

mermer

総合スコア16

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/11/14 06:41

編集2019/11/15 15:07

前提・実現したいこと

python3において
以下の条件を満たすようなリストを作成したいです.
・リスト内の要素の総和がn
・ある要素の和が与えられた条件を満たしている
・条件は要素の和が与えられる.与えられないものは基準値以下
作成するリストの長さが大きく,リストの要素の総和が大きいとき場合時間がかかってしまう(当たり前ですが...)
効率良く条件に合うリストを作り出すことはできないでしょうか?
現在は,リストの候補(総和n,リストの長さl_lenのリスト)をすべて計算し,その中から条件に合うものを結果として出力しています.

該当のソースコード

python

1from itertools import combinations_with_replacement 2n=20 #リストの要素の総和 3l_len = 5 #作成するリストの長さ 4lvalue = 2 #基準値 5check_dict = {frozenset([1,2,3]) : 12 , frozenset([0,2,4]) : 12 , frozenset([0,1]) : -1} #key:リストの要素のindex , value:keyが示すリストの要素の和(-1の場合基準値以下ならOK) 6result = [] #条件に合ったリストを格納するリスト 7#リストの要素の総和がn,作成するリストの長さがl_lenのリストの総組み合わせ 8for x in combinations_with_replacement(range(n+1), l_len-1): 9 t = [ed - st for st, ed in zip((0,) + x, x + (n,))] 10 #リストのチェック 11 for k,v in check_dict.items(): 12 s = 0 13 for index in k: 14 s += t[index] 15 if v == -1 and s > lvalue: 16 break 17 if v != -1 and s != v: 18 break 19 else: 20 result.append(t) 21result

今回の出力

[[0, 0, 4, 8, 8],
[0, 1, 4, 7, 8],
[0, 2, 4, 6, 8],
[1, 0, 4, 8, 7],
[1, 1, 4, 7, 7],
[2, 0, 4, 8, 6]]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kairi003

2019/11/16 10:22

質問なのですが,[0,0,0,0,20]みたいな要素も条件を満たしますよね?
kairi003

2019/11/16 10:32

すみません,条件の部分の理解が足りませんでした.大丈夫です. ただcheck_dictを辞書型である意味がないので素直に二次元タプルあたりにしたほうがいいと思います.
guest

回答1

0

ベストアンサー

こうなりました。

Python

1import time 2 3n=20 #リストの要素の総和 4l_len = 5 #作成するリストの長さ 5lvalue = 2 #基準値 6check_dict = {frozenset([1,2,3]) : 12 , frozenset([0,2,4]) : 12 , frozenset([0,1]) : -1} #key:リストの要素のindex , value:keyが示すリストの要素の和(-1の場合基準値以下ならOK) 7result = [] #条件に合ったリストを格納するリスト 8 9def f(n, l_len, lvalue, check_dict, result, temp = None, level = 0): 10 if temp is None: 11 # 初回呼び出し時の初期化 12 temp = [ 0 for _ in range(l_len)] 13 remain = n 14 else: 15 remain = n - sum(temp) 16 17 18 # 指定された添え字における候補を決定 19 possible = [ True for _ in range(remain + 1) ] 20 21 for k, v in check_dict.items(): 22 if level in k: 23 c_sum = sum([ temp[_] for _ in k]) 24 if v == -1: 25 # lvalueを超える組み合わせを要素 26 for i in range(lvalue - c_sum+1, remain + 1): 27 possible[i] = False 28 elif level == list(k)[-1]: 29 # 合計値指定のfrozensetの最後の場合は候補は一つ(v - c_sum)。それ以外を除外 30 for i in range(0, min(v - c_sum, remain + 1)): 31 possible[i] = False 32 for i in range(v - c_sum+1, remain + 1): 33 possible[i] = False 34 else: 35 # 合計値指定のfrozensetの途中の場合は上限を超える値を除外 36 for i in range(v - c_sum +1, remain + 1): 37 possible[i] = False 38 39 if level == (l_len - 1): 40 # リストの最後の場合は残りのみで判定 41 if possible[remain]: 42 temp[level] = remain 43 result.append(temp.copy()) 44 temp[level] = 0 45 else: 46 # 候補を使いながら再起呼び出し 47 for i in range(remain + 1): 48 if possible[i]: 49 temp[level] = i 50 f(n, l_len, lvalue, check_dict, result, temp, level+1) 51 temp[level] = 0 52 53start = time.time() 54f(n, l_len, lvalue, check_dict, result) 55elapsed_time = time.time() - start 56print(elapsed_time) 57print(result)

私の環境では質問欄コードは約20msに対して、回答コードは約1msになります。

投稿2019/11/23 04:35

編集2019/11/23 08:04
nomuken

総合スコア1627

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問