简体   繁体   English

元素方式'和'用于python中的列表?

[英]Element-wise 'and' for lists in python?

I have two lists: 我有两个清单:

X = [True,False]
Y = [True,True]

I am trying to compare X[0] with Y[0] and X[1] with Y[1]. 我试图将X [0]与Y [0]和X [1]与Y [1]进行比较。

I tried 我试过了

in [7]: X and Y
Out[7]: [True, True]

but the result I was expecting was [True,False]. 但我期待的结果是[真,假]。

What should I be doing? 我该怎么办?

This is a perfect opportunity to use map , because and can be represented with a built-in function: 这是使用map的绝佳机会,因为and可以用内置函数表示:

import operator
X = [True,False]
Y = [True,True]
map(operator.and_, X,Y)
#=> [True, False]

The reason why you get the behaviour you did is that and performs operations on the operands as if they had bool applied to them. 你得到你所做的行为的原因是, and操作数执行操作,就好像他们已经应用了bool一样。 All non-empty lists evaluate to True in a boolean context. 所有非空列表在布尔上下文中计算为True

As to the "list comprehension is always better" point: no it's not. 至于“列表理解总是更好”点:不,不是。 The equivalent list comprehension is: 等效列表理解是:

[x and y for x, y in zip(X, Y)]

Which has to build an intermediate object (either list or generator, depending on the python version), and still requires the reader to know what zip does, just as much as map does. 哪个必须构建一个中间对象(列表或生成器,取决于python版本),并且仍然需要读者知道zip作用,就像map一样。 It's also likely to be slightly slower (because map + builtin function is fast - it all happens in the C layer, essentially). 它也可能稍微慢一点(因为map + builtin函数很快 - 它本质上都发生在C层,基本上)。 In fact, timeit shows that izip is faster (see below), but I really think the readability point is more important; 实际上, timeit表明izip更快(见下文),但我认为可读性点更重要; you may also see different results if performance really matters. 如果表现真的很重要,你可能会看到不同的结果。

>>> timeit.timeit('map(operator.and_, X,Y)', 'import operator; import itertools; import random; X = [random.choice([True,False]) for _ in range(1000)]; Y = [random.choice([True,False]) for _ in range(1000)]', number=10000)
1.0160579681396484
>>> timeit.timeit('[x and y for x, y in zip(X, Y)]', 'import operator; import itertools; import random; X = [random.choice([True,False]) for _ in range(1000)]; Y = [random.choice([True,False]) for _ in range(1000)]', number=10000)
1.3570780754089355
>>> timeit.timeit('[x and y for x, y in itertools.izip(X, Y)]', 'import operator; import itertools; import random; X = [random.choice([True,False]) for _ in range(1000)]; Y = [random.choice([True,False]) for _ in range(1000)]', number=10000)
0.965054988861084

That said, if you need arbitrary numbers of lists, you need to use all in a list comprehension (or combined with izip directly); 也就是说,如果你需要任意数量的列表,你需要在列表理解中使用all (或直接与izip结合使用); and and_ is technically bitwise and, so be aware that might have funky results if working with numeric types other than bool . and_在技​​术上是按位的,因此请注意,如果使用除bool之外的数字类型,可能会有时髦的结果。

Here is an all version: 这是一个all版本:

import itertools
map(all,itertools.izip(X,Y,Z))

All non-empty lists evaluate to True in a boolean context, and and evaluates to the last expression it evaluated ( Y in this case), which is why you get the result you do. 所有非空列表评估为True在布尔上下文, and计算到最后表达它评估( Y在这种情况下),这就是为什么你会得到你的结果。 You want something like this: 你想要这样的东西:

[x and y for x, y in zip(X, Y)]

Suppose you have and arbitrary group of lists: 假设您有任意组列表:

A=[True, False, False]
B=[True, True, False]
C=[3,0,0]

Now write something that looks a bit like itertools.izip but allows a function to be added: 现在写一些看起来有点像itertools.izip的东西,但允许添加一个函数:

def elements(*iterables, **kwds):
    func=kwds.get('func', None)
    iterables=map(iter, iterables)
    while iterables:
        t=tuple(map(next, iterables)) 
        if func is not None:
            yield func(t)
        else:
            yield t 

Now add functions that will return the logical result of F(A[0],B[0],C[0]...) . 现在添加将返回F(A[0],B[0],C[0]...)的逻辑结果的函数。 For example, these each do the function described: 例如,这些都执行所描述的功能:

def ands(elements):
    ''' logical 'and' for all the elements'''
    return all(elements)

def ors(elements):
    ''' logical 'or' for all the elements'''
    return any(elements)

def bitand(elements):
    ''' bitwise 'and' for all the elements'''
    return reduce(operator.and_,elements)    

Then just call the function: 然后只需调用函数:

print list(elements(A,B,C,func=ands))  
# [True, False, False]

Or for you specific example: 或者为您提供具体示例:

print list(elements([True,False],[True,True],func=ands))  
# [True, False]

Or just use all directly: 或者直接使用all

print list(elements([True,False],[True,True],func=all))   
# [True, False]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM