質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

Q&A

解決済

1回答

1343閲覧

複数の関数をリストに格納する方法

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

0グッド

0クリップ

投稿2019/05/06 10:40

再帰の練習としてフィボナッチ数列の兄弟分たちの関数を作り、初期値が1つ多い関数は第何項で前の関数を超えるのかを調べています。
下記は、初期値がそれぞれ2, 3, 4つのfib(), trib(), tetr()と、trib()がfib()を超えるのはいつかを求めるコードです。

比較するのが2,3回なら良いのですが同様の関数を12個も作ってしまったので、while文の中を毎回書き換えるのが面倒です。
lst = [fib(), trib(), ... dod()]として関数をリストに入れてしまえば、for文を使ってlstiのように書けるのではないかと思い試してみたのですが、リストに入れた関数はint扱いになるようで期待したようには動作しませんでした。
リストでなくても構わないので、while文の関数名の代入を自動化する良い手段があればご教示ください。

Python

1# Fibonacci sequence (tail recursion ver.) 2def fib(n, f1=0, f2=1): 3 if n == 1: 4 return f1 5 elif n == 2: 6 return f2 7 return fib(n - 1, f2, f1 + f2) 8 9 10# Tribonacci sequence 11def trib(n, f1=0, f2=0, f3=1): 12 if n == 1 or n == 2: 13 return f1 14 elif n == 3: 15 return f3 16 else: 17 return trib(n - 1, f2, f3, f1 + f2 + f3) 18 19 20# Tetranacci sequence 21def tetr(n, f1=0, f2=0, f3=0, f4=1): 22 if n in list(range(1, 4)): 23 return f1 24 elif n == 4: 25 return f4 26 else: 27 return tetr(n - 1, f2, f3, f4, f1 + f2 + f3 + f4)

Python

1# Compare fib with trib 2cnt = 0 3while True: 4 cnt += 1 5 if fib(cnt) < trib(cnt): 6 print( 7 f"count: {cnt}\n" 8 f"digits: {len(str(trib(cnt)))}\n" 9 f"fib: {fib(cnt)}\n" 10 f"trib: {trib(cnt)}\n" 11 f"diff: {trib(cnt) - fib(cnt)}\n" 12 ) 13 break 14 15> count: 9 16> digits: 2 17> fib: 21 18> trib: 24 19> diff: 3

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

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

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

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

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

guest

回答1

0

ベストアンサー

lst = [fib(), trib(), ... dod()]として関数をリストに入れてしまえば、for文を使ってlstiのように書けるのではないかと思い試してみたのですが、リストに入れた関数はint扱いになる

それだと呼び出した結果がリストに格納されます。
呼び出さずに、関数オブジェクト自体を使ってやれば良いのです。

Python

1lst = [fib, trib, ..., dod]

追記

関数fib, trib, tetrなどの計算量が気になります。
functools.lru_cacheを利用するか、ジェネレータ関数として実装し直すことをお勧めします。

ランダムアクセスが必須なら前者、シーケンシャルアクセスで良いなら後者が良いでしょう。

書いてみた

面白そうだったので、個人的な趣味全開で書いてみました。

main.py

Python

1from fibonacci import gen_fibonacci_n 2from namedzip import NamedZip 3 4 5func_dct = dict(zip( 6 ['fib', 'trib', 'tetr'], map(gen_fibonacci_n, [2, 3, 4]) 7)) 8 9it = enumerate(NamedZip(**func_dct), start=1) 10for count, dct in it: 11 print('{:-^20s}'.format(f' count: {count:2d} ')) 12 for name, val in dct.items(): 13 print('{:6s} {:3d}'.format(f'{name}:', val)) 14 15 print() 16 17 # 18 if dct['fib'] < dct['trib']: 19 break

fibonacci.py

Python

1import collections 2import itertools 3 4 5def gen_fibonacci_n(n: int): 6 sequence = collections.deque( 7 itertools.repeat(0, n-1) 8 ) 9 sequence.append(1) 10 11 total = 1 12 while True: 13 yield sequence[0] 14 15 sequence.append(total) 16 total = 2 * total - sequence.popleft()

namedzip.py

Python

1class NamedZip: 2 def __init__(self, dct=None, **kwards): 3 if dct: 4 kwards = {**dct, **kwards} 5 6 self._names = kwards.keys() 7 self._iters = [ 8 iter(val) for val in kwards.values() 9 ] 10 11 def __iter__(self): 12 return self 13 14 def __next__(self): 15 return dict(zip( 16 self._names, [next(it) for it in self._iters] 17 ))

実行結果 Wandbox

plain

1---- count: 1 ----- 2fib: 0 3trib: 0 4tetr: 0 5 6---- count: 2 ----- 7fib: 1 8trib: 0 9tetr: 0 10 11---- count: 3 ----- 12fib: 1 13trib: 1 14tetr: 0 15 16---- count: 4 ----- 17fib: 2 18trib: 1 19tetr: 1 20 21---- count: 5 ----- 22fib: 3 23trib: 2 24tetr: 1 25 26---- count: 6 ----- 27fib: 5 28trib: 4 29tetr: 2 30 31---- count: 7 ----- 32fib: 8 33trib: 7 34tetr: 4 35 36---- count: 8 ----- 37fib: 13 38trib: 13 39tetr: 8 40 41---- count: 9 ----- 42fib: 21 43trib: 24 44tetr: 15

遠回りしている感が否めませんが、NamedZipは少し使いやすそう。

コメントを受けて

簡単な説明をコードに付け加えていただけると助かります。

デバッグプリントだけ加えておきました。

Python

1import collections 2import itertools 3 4 5def gen_fibonacci_n(n: int): 6 sequence = collections.deque( 7 itertools.repeat(0, n-1) 8 ) 9 sequence.append(1) 10 11 total = 1 12 while True: 13 print(sequence) 14 yield sequence[0] 15 16 sequence.append(total) 17 total = 2 * total - sequence.popleft() 18 19 20print('{:-^20s}'.format('fibonacci')) 21gen_fib = gen_fibonacci_n(2) 22for e in itertools.islice(gen_fib, 10): 23 print(e) 24 25print('{:-^20s}'.format('tribonacci')) 26gen_trib = gen_fibonacci_n(3) 27for e in itertools.islice(gen_trib, 10): 28 print(e)

実行結果 Wandbox

plain

1-----fibonacci------ 2deque([0, 1]) 30 4deque([1, 1]) 51 6deque([1, 2]) 71 8deque([2, 3]) 92 10deque([3, 5]) 113 12deque([5, 8]) 135 14deque([8, 13]) 158 16deque([13, 21]) 1713 18deque([21, 34]) 1921 20deque([34, 55]) 2134 22-----tribonacci----- 23deque([0, 0, 1]) 240 25deque([0, 1, 1]) 260 27deque([1, 1, 2]) 281 29deque([1, 2, 4]) 301 31deque([2, 4, 7]) 322 33deque([4, 7, 13]) 344 35deque([7, 13, 24]) 367 37deque([13, 24, 44]) 3813 39deque([24, 44, 81]) 4024 41deque([44, 81, 149]) 4244

dequeをn長のキューとして利用しています。

投稿2019/05/06 10:44

編集2019/05/07 01:03
LouiS0616

総合スコア35658

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

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

退会済みユーザー

退会済みユーザー

2019/05/06 10:49

迅速な回答ありがとうございます。 ()を外すだけで良いとは...これは盲点でした
退会済みユーザー

退会済みユーザー

2019/05/06 18:05

面白い追記をしてくださってありがとうございます。 ジェネレータ関数の仕組みを含め、教えてくださったコードが私の理解の範疇を超えているので簡単な説明をコードに付け加えていただけると助かります。お願いできますでしょうか? 計算量についても質問です。 私のコードは末尾再帰なのでO(n)だと思っていたのですが、誤解なのでしょうか? また、教えてくださったものだと計算量はどうなるのでしょう?
LouiS0616

2019/05/07 01:03 編集

> 私のコードは末尾再帰なのでO(n)だと思っていたのですが、誤解なのでしょうか? 確かにn項目の数値を求める計算量はO(n)です。 ただ、1番目、2番目、... 毎回O(n)の計算をしてしまっています。 例えば fib(5) を求める際は、直前に計算した fib(4) fib(3) の結果を利用すればO(1)です。 > 簡単な説明をコードに付け加えていただけると助かります。 本当に個人的な癖が出ているコードなので、参考になるのは gen_fibonacci_n くらいでしょう。 ちょっと追記しておきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問