web-dev-qa-db-fra.com

Trouver une paire différente dans une liste par python

J'ai une liste et je veux trouver une paire différente dans la liste . J'implémente une fonction -> different ()

import numpy as np


def different(array):
    res = []
    for (x1, y1), (x2, y2) in array:
        if (x1, y1) != (x2, y2):
            res.append([(x1, y1), (x2, y2)])
    return res


a = np.array([[[1, 2], [3, 4]],
              [[1, 2], [1, 2]],
              [[7, 9], [6, 3]],
              [[3, 3], [3, 3]]])

out = different(a)  # get [[(1, 2), (3, 4)],
                    #      [(7, 9), (6, 3)]]

Existe-t-il une autre façon de procéder? Je souhaite améliorer ma fonction différent .. La taille de la liste peut être supérieure à 100 000.

14
vincentlai

La façon numpy de le faire est

import numpy as np

a = np.array([[[1, 2], [3, 4]],
              [[1, 2], [1, 2]],
              [[7, 9], [6, 3]],
              [[3, 3], [3, 3]]])

b = np.logical_or(a[:,0,0] != a[:,1,0],  a[:,0,1] != a[:,1,1])

print(a[b])
8
Joe

Comparaison vectorisée

a[~(a[:, 0] == a[:, 1]).all(1)]

array([[[1, 2],
        [3, 4]],

       [[7, 9],
        [6, 3]]])

Cela fonctionne en prenant la première paire de chaque sous-tableau et en comparant chaque avec la deuxième paire. Tous les sous-tableaux pour lesquels des entrées non identiques seulement sont sélectionnées. Considérer,

a[:, 0] == a[:, 1]

array([[False, False],
       [ True,  True],
       [False, False],
       [ True,  True]])

A partir de là, nous voulons les lignes qui n'ont pas True à chaque colonne. Donc, sur ce résultat, utilisez all, puis annulez le résultat.

~(a[:, 0] == a[:, 1]).all(1)
array([ True, False,  True, False])

Cela vous donne un masque que vous pouvez ensuite utiliser pour sélectionner les sous-matrices de a.


np.logical_or.reduce

Semblable à la première option ci-dessus, mais aborde ce problème de l'autre côté (voir la loi de DeMorgan).

a[np.logical_or.reduce(a[:, 0] != a[:, 1], axis=1)]

6
coldspeed

Solutions temps comparaisons

Lorsqu'il existe autant d'approches différentes d'un problème, des comparaisons de temps peuvent vraiment aider à identifier les meilleures réponses.

Installer

Nous utilisons un tableau de taille (200000, 2, 2) sous la forme OP Vincentlai a souligné que sa taille est dans la plage de la taille attendue du tableau.

a = np.array(np.random.randint(10, size=(200000, 2, 2)))


Utiliser Joe answer: numpy.logical_and

%timeit b = a[np.logical_and(a[:,0,0] != a[:,1,0],  a[:,0,1] != a[:,1,1])]
>>> 5.12 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Utilisation de Coldspeed première réponse: comparaison vectorielle

%timeit b = a[~(a[:, 0] == a[:, 1]).all(1)]
>>> 13.7 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Utilisation de Coldspeed second answer: numpy.logical_or

%timeit b = a[np.logical_or.reduce(a[:, 0] != a[:, 1], axis=1)]
>>> 13.2 ms ± 498 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Utilisation de U9 Transférer answer: filtres

%timeit b = list(filter(lambda x: x[0]!=x[1],a.tolist()))
>>> 102 ms ± 4.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Utilisation de aydow answer: filtres

%timeit b = [[(x1, y1), (x2, y2)] for (x1, y1), (x2, y2) in a if (x1, y1) != (x2, y2)]
>>> 752 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


Conclusions

L'approche de Joe avec numpy.logical_and est de loin la plus rapide. Comme on pouvait s'y attendre, chaque approche complète en python est extrêmement courte.

3
Luca Cappelletti

En utilisant la compréhension de liste sur une ligne, on peut faire comme ci-dessous,

items_list = [[[1, 2], [3, 4]],
              [[1, 2], [1, 2]],
              [[7, 9], [6, 3]],
              [[3, 3], [3, 3]]
             ]

# Output
[itm for itm in items_list if itm[0] != itm[1]]
1

Essayez d’utiliserfilter:

import numpy as np

def different(array):   
   return list(filter(lambda x: x[0]!=x[1],array.tolist()))

a = np.array([[[1, 2], [3, 4]],
              [[1, 2], [1, 2]],
              [[7, 9], [6, 3]],
              [[3, 3], [3, 3]]])

out = different(a)
print(out)
1
U9-Forward

Utiliser une liste de compréhension

def different(array):
    return [[(x1, y1), (x2, y2)] for (x1, y1), (x2, y2) in array if (x1, y1) != (x2, y2)]
0
aydow