如何更简洁地找到缺失值?

75 投票
11 回答
3307 浏览
提问于 2025-04-17 09:52

下面的代码用来检查变量 xy 是否是不同的值(这些变量 xyz 只能取值 abc),如果是不同的,就把 z 设置为第三个字符:

if x == 'a' and y == 'b' or x == 'b' and y == 'a':
    z = 'c'
elif x == 'b' and y == 'c' or x == 'c' and y == 'b':
    z = 'a'
elif x == 'a' and y == 'c' or x == 'c' and y == 'a':
    z = 'b'

有没有更简洁、更易读、更高效的方法来实现这个功能呢?

11 个回答

27

Sven的代码做得很好,但有点过于复杂了,其实可以用元组解包来代替pop()。另外,还可以加一个检查条件if x != y,来确认xy是不同的。下面是改进后的代码:

# create the set just once
choices = {'a', 'b', 'c'}

x = 'a'
y = 'b'

# the main code can be used in a loop
if x != y:
    z, = choices - {x, y}

这里有一个时间测试的对比,展示了不同代码的性能:

import timeit, itertools

setup_template = '''
x = %r
y = %r
choices = {'a', 'b', 'c'}
'''

new_version = '''
if x != y:
    z, = choices - {x, y}
'''

original_version = '''
if x == 'a' and y == 'b' or x == 'b' and y == 'a':
    z = 'c'
elif x == 'b' and y == 'c' or x == 'c' and y == 'b':
    z = 'a'
elif x == 'a' and y == 'c' or x == 'c' and y == 'a':
    z = 'b'
'''

for x, y in itertools.product('abc', repeat=2):
    print '\nTesting with x=%r and y=%r' % (x, y)
    setup = setup_template % (x, y)
    for stmt, name in zip([original_version, new_version], ['if', 'set']):
        print min(timeit.Timer(stmt, setup).repeat(7, 100000)),
        print '\t%s_version' % name

这是时间测试的结果:

Testing with x='a' and y='a'
0.0410830974579     original_version
0.00535297393799    new_version

Testing with x='a' and y='b'
0.0112571716309     original_version
0.0524711608887     new_version

Testing with x='a' and y='c'
0.0383319854736     original_version
0.048309803009      new_version

Testing with x='b' and y='a'
0.0175108909607     original_version
0.0508949756622     new_version

Testing with x='b' and y='b'
0.0386209487915     original_version
0.00529098510742    new_version

Testing with x='b' and y='c'
0.0259420871735     original_version
0.0472128391266     new_version

Testing with x='c' and y='a'
0.0423510074615     original_version
0.0481910705566     new_version

Testing with x='c' and y='b'
0.0295209884644     original_version
0.0478219985962     new_version

Testing with x='c' and y='c'
0.0383579730988     original_version
0.00530385971069    new_version

这些测试结果显示,原始版本的性能会根据不同的输入值触发的条件语句而有很大的变化。

47

strip 方法是一个快速的选择,对我来说效果很好:

z = 'abc'.strip(x+y) if x!=y else None
62
z = (set(("a", "b", "c")) - set((x, y))).pop()

我假设你代码中的三种情况之一是成立的。如果是这样,set(("a", "b", "c")) - set((x, y)) 这个集合将只包含一个元素,而这个元素会通过 pop() 方法返回。

补充:正如Raymond Hettinger在评论中提到的,你也可以使用元组解包来提取集合中的那个单一元素:

z, = set(("a", "b", "c")) - set((x, y))

撰写回答