[英]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.