[英]Finding two integers that multiply to 20. Can I make this code more “pythonic”?
我做了這個代碼,在所說的列表中找到兩個整數(在這種情況下為[2,4,5,1,6,40,-1]),乘以二十。 我在開始時遇到了一點困難,但添加一個功能解決了我的問題。 我向我的一位朋友展示了這段代碼,他是一名程序員,他說我可以讓這段代碼更“pythonic”,但我不知道如何。
這是代碼:
num_list = [2,4,5,1,6,40,-1]
def get_mult_num(given_list):
for i in given_list:
for j in range(i+1, len(given_list)): #for j not to be == i and to be in the list
mult_two_numbers = i * j
if mult_two_numbers == 20:
return i,j
print(get_mult_num(num_list))
我不一定認為它是'unpythonic',你使用標准的Python慣用語循環數據並生成單個結果或None
。 Pythonic這個詞是模糊的,一個主題是“當我看到它時我知道它”的參數。
並不是說你產生了正確的實現。 當i
循環遍歷given_numbers
, j
循環遍歷從i + 2
到len(given_numbers)
的整數,將given_list
值與索引混合? 對於你的樣本輸入,你從半開范圍[4,7],[6,7],[7,7](空),[3,7],[8,7](空)中取j
,[42,7](空)和[1,7]。 它產生正確的答案在所有的運氣,不是由於正確性; 如果你給你的功能列表[2, 10]
,它將找不到解決方案! 你想再次遍歷given_numbers
,限制切片,或者從i
的當前索引開始生成索引,但是你的外部循環也需要添加一個enumerate()
調用:
for ii, i in enumerate(given_numbers):
for j in given_numbers[ii + 1:]:
# ...
要么
for ii, i in enumerate(given_numbers):
for jj in range(ii + 1, len(given_numbers)):
j = given_numbers[jj]
# ...
所有這些都沒有那么高效; Python標准庫為您提供了生成i, j
對而無需嵌套for
循環或切片或其他形式的過濾的工具。
你的雙循環應該生成整數輸入的組合 ,所以使用itertools.combinations()
對象生成唯一的i, j
對:
from itertools import combinations
def get_mult_num(given_list):
return [(i, j) for i, j in combinations(given_list, 2) if i * j == 20]
這假設可以存在零個或多個這樣的解決方案,而不僅僅是單個解決方案。
如果您只需要第一個結果或None
,則可以使用next()
函數 :
def get_mult_num(given_list):
multiplies_to_20 = (
(i, j) for i, j in combinations(given_list, 2)
if i * j == 20)
return next(multiplies_to_20, None)
接下來,您可能想要反轉問題,而不是生成所有可能的組合。 如果將given_list
轉換為一個集合,您可以輕松地檢查目標數字20是否可以干凈地划分,沒有任何給定數字的余數,並且除法的結果更大,並且也是數字集合中的整數。 這給你一個線性時間的答案。
您可以通過除以小於目標值的平方根的數字來進一步限制搜索,因為您將找不到更大的值來匹配您的輸入數字(給定數字n
和它的平方根s
,根據定義s * (s + 1)
將大於n
)。
如果我們為函數添加目標數的參數並使其成為生成器函數 ,那么您將獲得:
def gen_factors_for(target, numbers):
possible_j = set(numbers)
limit = abs(target) ** 0.5
for i in numbers:
if abs(i) < limit and target % i == 0:
j = target // i
if j in possible_j and abs(j) > abs(i):
yield i, j
這種方法比測試的所有排列,特別是如果你需要查找所有可能的因素快得多 。 請注意,我在這里創建了兩個函數生成器以進行比較:
>>> import random, operator
>>> from timeit import Timer
>>> def gen_factors_for_division(target, numbers):
... possible_j = set(numbers)
... limit = abs(target) ** 0.5
... for i in numbers:
... if abs(i) < limit and target % i == 0:
... j = target // i
... if j in possible_j and abs(j) > abs(i):
... yield i, j
...
>>> def gen_factors_for_combinations(target, given_list):
... return ((i, j) for i, j in combinations(given_list, 2) if i * j == target)
...
>>> numbers = [random.randint(-10000, 10000) for _ in range(100)]
>>> targets = [operator.mul(*random.sample(set(numbers), 2)) for _ in range(5)]
>>> targets += [t + random.randint(1, 100) for t in targets] # add likely-to-be-unsolvable numbers
>>> for (label, t) in (('first match:', 'next({}, None)'), ('all matches:', 'list({})')):
... print(label)
... for f in (gen_factors_for_division, gen_factors_for_combinations):
... test = t.format('f(t, n)')
... timer = Timer(
... f"[{test} for t in ts]",
... 'from __main__ import targets as ts, numbers as n, f')
... count, total = timer.autorange()
... print(f"{f.__name__:>30}: {total / count * 1000:8.3f}ms")
...
first match:
gen_factors_for_division: 0.219ms
gen_factors_for_combinations: 4.664ms
all matches:
gen_factors_for_division: 0.259ms
gen_factors_for_combinations: 3.326ms
請注意,我會生成10個不同的隨機目標,以避免兩種方法都出現幸運的最佳情況。
[(i,j) for i in num_list for j in num_list if i<j and i*j==20]
我可以想到使用list-comprehension。 如果它們存在於給定列表中,這也有助於找到多個這樣的對。
num_list = [2,4,5,1,6,40,-1]
mult_num = [(num_list[i],num_list[j]) for i in range(len(num_list)) for j in range(i+1, len(num_list)) if num_list[i]*num_list[j] == 20]
print mult_num
輸出:
[(4, 5)]
您可以通過使用itertools.combinations而不是嵌套循環來使其更加pythonic,以查找所有數字對。 並非總是如此,但經常迭代索引, for i in range(len(L)):
比直接迭代值更少pythonic,就像for v in L:
中for v in L:
。
Python還允許你通過yield
關鍵字將你的函數變成一個生成器,這樣你就可以通過遍歷函數調用來獲得每一對,而不是只返回乘以20的第一對。
import itertools
def factors(x, numbers):
""" Generate all pairs in list of numbers that multiply to x.
"""
for a, b in itertools.combinations(numbers, 2):
if a * b == x:
yield (a, b)
numbers = [2, 4, 5, 1, 6, 40, -1]
for pair in factors(20, numbers):
print(pair)
我想出了這個。 它稍微改變了方法,因為它在num_list
搜索迭代值val
將乘以20所需的配對伙伴。 這使得代碼更容易,並且不需要導入,即使它不是最有效的方式。
for val in num_list:
if 20 / val in num_list:
print(val, int(20/val))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.