Python 这一组所有的一行函数在做什么?
我在上找到了这个单行函数,它创建了一组可以从作为参数传递的列表中创建的所有集合Python 这一组所有的一行函数在做什么?,python,lambda,set,list-comprehension,Python,Lambda,Set,List Comprehension,我在上找到了这个单行函数,它创建了一组可以从作为参数传递的列表中创建的所有集合 f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2**len(set(x)))] 有人能解释一下这个函数是如何工作的吗?要构造powerset,迭代2**len(set(x))会给出集合的所有二进制组合 range(2**len(set(x))) == [00000, 00001, 0
f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2**len(set(x)))]
有人能解释一下这个函数是如何工作的吗?要构造powerset,迭代
2**len(set(x))
会给出集合的所有二进制组合
range(2**len(set(x))) == [00000, 00001, 00010, ..., 11110, 11111]
现在,您只需测试该位是否在i
中设置,以查看是否需要将其包括在该集中,例如:
>>> i = 0b10010
>>> [y for j, y in enumerate(range(5)) if (i >> j) & 1]
[1, 4]
虽然我不确定每次迭代调用set(x)
的效率有多高。有一个小技巧可以避免:
f = lambda x: [[y for j, y in enumerate(s) if (i >> j) & 1] for s in [set(x)] for i in range(2**len(s))]
使用itertools
的两个其他表单:
import itertools as it
f1 = lambda x: [list(it.compress(s, i)) for s in [set(x)] for i in it.product((0,1), repeat=len(s))]
f2 = lambda x: list(it.chain.from_iterable(it.combinations(set(x), r) for r in range(len(set(x))+1)))
注意:如果您删除list()
,最后一个选项可能会返回一个iterable vs list,这取决于使用情况,这可能会节省一些内存
查看25个0-50随机数列表的一些计时:
%%timeit binary: 1 loop, best of 3: 20.1 s per loop
%%timeit binary+hack: 1 loop, best of 3: 17.9 s per loop
%%timeit compress/product: 1 loop, best of 3: 5.27 s per loop
%%timeit chain/combinations: 1 loop, best of 3: 659 ms per loop
要构造powerset,在
2**len(set(x))
上迭代可以得到集合的所有二进制组合
range(2**len(set(x))) == [00000, 00001, 00010, ..., 11110, 11111]
现在,您只需测试该位是否在i
中设置,以查看是否需要将其包括在该集中,例如:
>>> i = 0b10010
>>> [y for j, y in enumerate(range(5)) if (i >> j) & 1]
[1, 4]
虽然我不确定每次迭代调用set(x)
的效率有多高。有一个小技巧可以避免:
f = lambda x: [[y for j, y in enumerate(s) if (i >> j) & 1] for s in [set(x)] for i in range(2**len(s))]
使用itertools
的两个其他表单:
import itertools as it
f1 = lambda x: [list(it.compress(s, i)) for s in [set(x)] for i in it.product((0,1), repeat=len(s))]
f2 = lambda x: list(it.chain.from_iterable(it.combinations(set(x), r) for r in range(len(set(x))+1)))
注意:如果您删除list()
,最后一个选项可能会返回一个iterable vs list,这取决于使用情况,这可能会节省一些内存
查看25个0-50随机数列表的一些计时:
%%timeit binary: 1 loop, best of 3: 20.1 s per loop
%%timeit binary+hack: 1 loop, best of 3: 17.9 s per loop
%%timeit compress/product: 1 loop, best of 3: 5.27 s per loop
%%timeit chain/combinations: 1 loop, best of 3: 659 ms per loop
让我们重写一下,然后一步一步地分解:
f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2**len(set(x)))]
相当于:
def f(x):
n = len(set(x))
sets = []
for i in range(n): # all combinations of members of the set in binary
set_i = []
for j, y in enumerate(set(x)):
if (i>>j) & 1: #check if bit nr j is set
set_x.append(y)
sets.append(set_i)
return sets
对于像[1,2,3,4]
这样的输入列表,会发生以下情况:
n=4
range(2**n)=[0,1,2,3...15]
以二进制形式表示:
0,1,10,11,100...1110,1111
Enumerate使用其索引生成y的元组,因此在本例中:
[(0,1),(1,2),(2,3),(3,4)]
(i>>j)&1
部分可能需要一些解释。
(i>>j)
将数字i
j
向右移位,例如十进制:4>>2=1
,或二进制:100>>2=001
。&
是按位和
运算符。这将检查两个操作数的每一位是否为1,并以数字形式返回结果,就像过滤器一样:10111&11001=10101
在本例中,它检查位置
j
处的位是否为1。如果是,则将相应的值添加到结果列表中。通过这种方式,组合的二进制映射将转换为列表列表,并返回该列表。让我们稍微重写它,然后一步一步地将其分解:
f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2**len(set(x)))]
相当于:
def f(x):
n = len(set(x))
sets = []
for i in range(n): # all combinations of members of the set in binary
set_i = []
for j, y in enumerate(set(x)):
if (i>>j) & 1: #check if bit nr j is set
set_x.append(y)
sets.append(set_i)
return sets
对于像[1,2,3,4]
这样的输入列表,会发生以下情况:
n=4
range(2**n)=[0,1,2,3...15]
以二进制形式表示:
0,1,10,11,100...1110,1111
Enumerate使用其索引生成y的元组,因此在本例中:
[(0,1),(1,2),(2,3),(3,4)]
(i>>j)&1
部分可能需要一些解释。
(i>>j)
将数字i
j
向右移位,例如十进制:4>>2=1
,或二进制:100>>2=001
。&
是按位和
运算符。这将检查两个操作数的每一位是否为1,并以数字形式返回结果,就像过滤器一样:10111&11001=10101
在本例中,它检查位置
j
处的位是否为1。如果是,则将相应的值添加到结果列表中。这样,组合的二进制映射将转换为列表列表,然后返回。我知道如何运行该函数。我只是不明白如何编写代码来生成一组所有的集合。根据我已经知道的,(I>>j)&1将I的二进制位向右移动j次,然后执行I和1的位和。我不理解所有这些与实际创建结果集的相关性。我知道如何运行函数。我只是不明白如何编写代码来生成一组所有的集合。根据我已经知道的,(I>>j)&1将I的二进制位向右移动j次,然后执行I和1的位和。我不明白所有这些与实际创建结果集的相关性。