以下代码检查x
和y
是否为不同的值(变量x
,y
,z
只能包含值a
},b
或c
)如果是这样,请将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'
是否可以以更简洁,可读和有效的方式做到这一点?
答案 0 :(得分: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))
答案 1 :(得分:47)
strip
方法是另一个快速运行的选项:
z = 'abc'.strip(x+y) if x!=y else None
答案 2 :(得分:27)
Sven的优秀代码只做了太多的工作,并且可以使用元组解包而不是 pop()。此外,它可能添加了一个警卫if x != y
来检查 x 和 y 是否不同。以下是改进后的答案:
# 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
这些时序表明原始版本的性能会有很大差异,具体取决于各种输入值触发的if语句。
答案 3 :(得分:18)
z = (set('abc') - set(x + y)).pop()
以下是显示其有效的所有方案:
>>> (set('abc') - set('ab')).pop() # x is a/b and y is b/a
'c'
>>> (set('abc') - set('bc')).pop() # x is b/c and y is c/b
'a'
>>> (set('abc') - set('ac')).pop() # x is a/c and y is c/a
'b'
答案 4 :(得分:15)
如果相关的三个项目不是"a"
,"b"
和"c"
,而是1
,2
和3
,你也可以使用二进制异或:
z = x ^ y
更一般地说,如果您想将z
设置为三个数字a
,b
和c
中的剩余一个,则会给出两个数字x
和{ {1}}来自此集合,您可以使用
y
当然,如果数字是固定的,您可以预先计算z = x ^ y ^ a ^ b ^ c
。
此方法也可以与原始字母一起使用:
a ^ b ^ c
示例:
z = chr(ord(x) ^ ord(y) ^ 96)
不要指望任何阅读此代码的人立即弄清楚它的含义:)
答案 5 :(得分:13)
我认为Sven Marnach和F.J的解决方案很漂亮,但在我的小测试中并不快。这是Raymond使用预先计算的set
:
$ python -m timeit -s "choices = set('abc')" \
-s "x = 'c'" \
-s "y = 'a'" \
"z, = choices - set(x + y)"
1000000 loops, best of 3: 0.689 usec per loop
这是最初的解决方案:
$ python -m timeit -s "x = 'c'" \
-s "y = 'a'" \
"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'"
10000000 loops, best of 3: 0.310 usec per loop
请注意,这是if
- 语句的最差可能输入,因为必须尝试所有六个比较。使用x
和y
的所有值进行测试得出:
x = 'a', y = 'b': 0.084 usec per loop
x = 'a', y = 'c': 0.254 usec per loop
x = 'b', y = 'a': 0.133 usec per loop
x = 'b', y = 'c': 0.186 usec per loop
x = 'c', y = 'a': 0.310 usec per loop
x = 'c', y = 'b': 0.204 usec per loop
基于set
的变体显示了不同输入的相同性能,但它始终在 2到8倍之间。原因是基于if
的变体运行更简单的代码:与散列相比的相等测试。
我认为这两种类型的解决方案都很有价值:重要的是要知道创建“复杂”数据结构(如集合)会让您在性能方面付出代价 - 同时它们会为您提供大量可读性和开发速度。当代码改变时,复杂的数据类型也会好得多:很容易将基于集合的解决方案扩展到四个,五个......变量,而if语句很快变成维护噩梦。
答案 6 :(得分:8)
z = 'a'*('a' not in x+y) or 'b'*('b' not in x+y) or 'c'
或更少hackish并使用条件分配
z = 'a' if ('a' not in x+y) else 'b' if ('b' not in x+y) else 'c'
但是dict解决方案可能更快......你必须计时。
答案 7 :(得分:8)
使用词典尝试此选项:
z = {'ab':'c', 'ba':'c', 'bc':'a', 'cb':'a', 'ac':'b', 'ca':'b'}[x+y]
当然,如果地图中没有x+y
键,则会产生KeyError
,您必须处理它。
如果字典预先计算并存储以供将来使用,则访问速度会快得多,因为不需要为每个评估创建新的数据结构,只需要字符串连接和字典查找:< / p>
lookup_table = {'ab':'c', 'ba':'c', 'bc':'a', 'cb':'a', 'ac':'b', 'ca':'b'}
z = lookup_table[x+y]
答案 8 :(得分:2)
我认为应该是这样的:
z = (set(("a", "b", "c")) - set((x, y))).pop() if x != y else None
答案 9 :(得分:1)
使用列表理解,假设您的代码中的三个案例之一与其他人一样:
l = ['a', 'b', 'c']
z = [n for n in l if n not in [x,y]].pop()
或者,就像在接受的答案中一样,利用元组来解压缩它,
z, = [n for n in l if n not in [x,y]]
答案 10 :(得分:0)
看看是否有效
if a not in xy
z= 'a'
if b not in xy
z='b'
if c not in xy
z='c'