76 votes

Comment puis-je trouver la valeur manquante de manière plus concise ?

Le code suivant vérifie si x y y sont des valeurs distinctes (les variables x , y , z ne peuvent avoir que des valeurs a , b ou c ) et, dans l'affirmative, définit z au troisième caractère :

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'

Est-il possible de le faire d'une manière plus concise, plus lisible et plus efficace ?

62voto

Sven Marnach Points 133943
z = (set(("a", "b", "c")) - set((x, y))).pop()

Je suppose que l'un des trois cas de votre code est valable. Si c'est le cas, l'ensemble set(("a", "b", "c")) - set((x, y)) consistera en un seul élément, qui sera renvoyé par la fonction pop() .

Editar: Comme l'a suggéré Raymond Hettinger dans les commentaires, vous pouvez également utiliser le déballage de tuple pour extraire l'élément unique de l'ensemble :

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

47voto

chepner Points 54078

El strip est une autre option qui fonctionne rapidement pour moi :

z = 'abc'.strip(x+y) if x!=y else None

27voto

Raymond Hettinger Points 50330

L'excellent code de Sven faisait juste un peu trop de travail et aurait dû utiliser le déballage de tuple au lieu de pop() . Aussi, il aurait pu ajouter un garde if x != y pour vérifier x y y étant distincts. Voici à quoi ressemble la réponse améliorée :

# 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}

Voici les chronologies comparatives avec une suite de chronologie pour montrer la performance relative :

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

Voici les résultats des timings :

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

Ces chronologies montrent que le version originale Les performances varient considérablement en fonction des états if qui sont déclenchés par les différentes valeurs d'entrée.

18voto

Andrew Clark Points 77748
z = (set('abc') - set(x + y)).pop()

Voici tous les scénarios pour montrer que cela fonctionne :

>>> (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'

15voto

Sven Marnach Points 133943

Si les trois articles en question n'étaient pas "a" , "b" y "c" mais plutôt 1 , 2 y 3 vous pouvez également utiliser un XOR binaire :

z = x ^ y

De manière plus générale, si vous souhaitez définir z à l'un des trois numéros restants a , b y c étant donné deux nombres x y y de cet ensemble, vous pouvez utiliser

z = x ^ y ^ a ^ b ^ c

Bien sûr, vous pouvez précalculer a ^ b ^ c si les chiffres sont fixes.

Cette approche peut également être utilisée avec les lettres originales :

z = chr(ord(x) ^ ord(y) ^ 96)

Exemple :

>>> chr(ord("a") ^ ord("c") ^ 96)
'b'

Ne vous attendez pas à ce que quiconque lisant ce code comprenne immédiatement ce qu'il signifie :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X