Quelle est la manière la plus élégante et concise (sans créer ma propre classe avec surcharge d'opérateur) pour effectuer l'arithmétique de Tuple en Python 2.7?
Disons que j'ai deux tuples:
a = (10, 10)
b = (4, 4)
Mon résultat escompté est
c = a - b = (6, 6)
J'utilise actuellement:
c = (a[0] - b[0], a[1] - b[1])
J'ai aussi essayé:
c = Tuple([(i - j) for i in a for j in b])
mais le résultat était (6, 6, 6, 6)
. Je crois que ce qui précède fonctionne comme une imbriquée pour les boucles résultant en 4 itérations et 4 valeurs dans le résultat.
Si vous cherchez rapide, vous pouvez utiliser numpy:
>>> import numpy
>>> numpy.subtract((10, 10), (4, 4))
array([6, 6])
et si vous voulez le garder dans un tuple:
>>> Tuple(numpy.subtract((10, 10), (4, 4)))
(6, 6)
Une option serait,
>>> from operator import sub
>>> c = Tuple(map(sub, a, b))
>>> c
(6, 6)
Et itertools.imap
peut servir de remplacement pour map
.
Bien sûr, vous pouvez également utiliser d'autres fonctions de operator
à add
, mul
, div
, etc.
Mais j'envisagerais sérieusement de passer à une autre structure de données car je ne pense pas que ce type de problème soit adapté à Tuple
s
Utilisez Zip
et une expression de générateur:
c = Tuple(x-y for x, y in Zip(a, b))
Démo:
>>> a = (10, 10)
>>> b = (4, 4)
>>> c = Tuple(x-y for x, y in Zip(a, b))
>>> c
(6, 6)
Utilisation itertools.izip
pour une solution efficace en mémoire.
aide sur Zip
:
>>> print Zip.__doc__
Zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each Tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
Cela peut également être fait aussi bien sans importation, bien que lambda soit souvent indésirable:
Tuple(map(lambda x, y: x - y, a, b))
Si vous cherchez à obtenir la distance entre deux points sur un plan de coordonnées 2d par exemple, vous devez utiliser la valeur absolue de la soustraction des paires.
Tuple(map(lambda x ,y: abs(x - y), a, b))
JFYI, temps d'exécution dans mon ordinateur portable à 100 000 fois l'itération
np.subtract(a, b)
: 0,18578505516052246
Tuple(x - y for x, y in Zip(a, b))
: 0,09348797798156738
Tuple(map(lambda x, y: x - y, a, b))
: 0,07900381088256836
from operator import sub Tuple(map(sub, a, b))
: 0,044342041015625
l'opérateur est plus élégant pour moi.
En plus de la réponse de Kohei Kawasaki, pour la vitesse, la solution originale était en fait la plus rapide.
>>> timeit.timeit('Tuple(map(add, a, b))',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.6502681339999867
>>> timeit.timeit('(a[0] - b[0], a[1] - b[1])',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.19015854899998885
>>>
mon aide arithmétique Tuple élément par élément
opérations prises en charge: +, -, /, *, d
operation = 'd' calcule la distance entre deux points sur un plan de coordonnées 2D
def tuplengine(Tuple1, Tuple2, operation):
"""
quick and dirty, element-wise, Tuple arithmetic helper,
created on Sun May 28 07:06:16 2017
...
Tuple1, Tuple2: [named]tuples, both same length
operation: '+', '-', '/', '*', 'd'
operation 'd' returns distance between two points on a 2D coordinate plane (absolute value of the subtraction of pairs)
"""
assert len(Tuple1) == len(Tuple2), "Tuple sizes doesn't match, Tuple1: {}, Tuple2: {}".format(len(Tuple1), len(Tuple2))
assert isinstance(Tuple1, Tuple) or Tuple in type(Tuple1).__bases__, "Tuple1: not a [named]Tuple"
assert isinstance(Tuple2, Tuple) or Tuple in type(Tuple2).__bases__, "Tuple2: not a [named]Tuple"
assert operation in list("+-/*d"), "operation has to be one of ['+','-','/','*','d']"
return eval("Tuple( a{}b for a, b in Zip( Tuple1, Tuple2 ))".format(operation)) \
if not operation == "d" \
else eval("Tuple( abs(a-b) for a, b in Zip( Tuple1, Tuple2 ))")