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

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

詳細はこちら
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Python

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

Q&A

解決済

1回答

1584閲覧

リストを使わずyieldを使って数列を生成したい

naomi3

総合スコア1105

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Python

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

0グッド

0クリップ

投稿2019/10/20 05:35

ある画像処理用のアルゴリズムのPythonによる実装です。目的の数列は得られるのですが、リストを使っているためにメモリ効率が悪いです。Pythonにはジェネレータがあることを知り、リストを使わずyieldを使ってスマートにメモリ効率の良いコードが書けるのではないかと思ったのですが、Pythonを学んで日が浅く、わからずにいます。

Python

1import sys 2 3 4def create(depth, left, right): 5 if left > right: 6 return None 7 else: 8 return bin_node(depth + 1, left, right) 9 10 11def bin_node(depth, left, right): 12 center = (left + right) // 2 13 return { 14 'depth': depth, 15 'center': center, 16 'leftNode': create(depth, left, center - 1), 17 'rightNode': create(depth, center + 1, right) 18 } 19 20 21def get_max_depth(node): 22 if node is None: 23 return 0 24 else: 25 return max([node['depth'], get_max_depth(node['leftNode']), get_max_depth(node['rightNode'])]) 26 27 28def traverse_in_depth(node, depth): 29 list = [] 30 if node is not None and node['depth'] == depth: 31 list.append(node['center']) 32 elif node is not None and node['depth'] < depth: 33 list.extend(traverse_in_depth(node['leftNode'], depth)) 34 list.extend(traverse_in_depth(node['rightNode'], depth)) 35 return list 36 37 38def bin_node_iterator(left, right): 39 root_node = create(0, left, right) 40 41 max_depth = get_max_depth(root_node) 42 43 list = [] 44 for depth in range(1, max_depth + 1): 45 list.extend(traverse_in_depth(root_node, depth)) 46 47 return list 48 49 50left = int(sys.argv[1]) 51right = int(sys.argv[2]) 52print(left, right) 53for n in bin_node_iterator(left, right): 54 print(n, end=" ")

試したこと
(traverse_in_depth関数、bin_node_iterator関数以外は同じ)

Python

1def traverse_in_depth(node, depth): 2 if node is not None and node['depth'] == depth: 3 yield node['center'] 4 elif node is not None and node['depth'] < depth: 5 yield traverse_in_depth(node['leftNode'], depth) 6 yield traverse_in_depth(node['rightNode'], depth) 7 8 9def bin_node_iterator(left, right): 10 root_node = create(0, left, right) 11 12 max_depth = get_max_depth(root_node) 13 14 for depth in range(1, max_depth + 1): 15 yield traverse_in_depth(root_node, depth)

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

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

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

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

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

guest

回答1

0

ベストアンサー

◯ 提案

全体のコードを読めていないので、直るかはわからないのですが
traverse_in_depth 関数を呼び出す際に yield from を使ってみると、どうでしょうか?

# 修正前 def traverse_in_depth(node, depth): if node is not None and node['depth'] == depth: yield node['center'] elif node is not None and node['depth'] < depth: yield traverse_in_depth(node['leftNode'], depth) yield traverse_in_depth(node['rightNode'], depth) def bin_node_iterator(left, right): root_node = create(0, left, right) max_depth = get_max_depth(root_node) for depth in range(1, max_depth + 1): yield traverse_in_depth(root_node, depth)
# 修正後 def traverse_in_depth(node, depth): if node is not None and node['depth'] == depth: yield node['center'] elif node is not None and node['depth'] < depth: yield from traverse_in_depth(node['leftNode'], depth) # <--- yield from を使います。 yield from traverse_in_depth(node['rightNode'], depth) # <--- yield from を使います。 def bin_node_iterator(left, right): root_node = create(0, left, right) max_depth = get_max_depth(root_node) for depth in range(1, max_depth + 1): yield from traverse_in_depth(root_node, depth) # <--- yield from を使います。

◯ 補足

yield を使った関数を「ジェネレータ関数」と言います。
「ジェネレータ関数」は「ジェネレータイテレータ」というオブジェクトを返します。

traverse_in_depth 関数は「ジェネレータイテレータ」を返しています。
修正前の bin_node_iterator 関数は traverse_in_depth 関数が返した
「ジェネレータイテレータ」を1つずつ返してしまっています。

python

1# コピペで動きます。 2def f(): 3 yield g1() 4 yield g2() 5 6def g1(): 7 yield 0 8 yield 1 9 10def g2(): 11 yield 2 12 yield 3 13 14[i for i in f()] 15# [<generator object g1 at 0x100e9db48>, <generator object g2 at 0x100e9dba0>]

今回は「ジェネレータイテレータ」の 中身 が欲しいので、
yield from を使います。

python

1# コピペで動きます。 2def f(): 3 yield from g1() 4 yield from g2() 5 6def g1(): 7 yield 0 8 yield 1 9 10def g2(): 11 yield 2 12 yield 3 13 14[i recursive.pyfor i in f()] 15# [0, 1, 2, 3]

投稿2019/10/20 06:13

編集2019/10/20 06:42
nico25

総合スコア830

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

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

naomi3

2019/10/20 06:36

ご回答ありがとうございます。ですが、動作しません。よろしくお願いいたします。
nico25

2019/10/20 06:45

既に試されているかもしれないのですが、 traverse_in_depth が再帰呼び出し担っているのを見落としていました。 2 箇所 yield from を追記いたしました。 これでも動くかはわからないのですが、いかがでしょうか。
naomi3

2019/10/20 06:52

ありがとうございます。 うまく動きました。
nico25

2019/10/20 07:05

よかったです :)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問