Найти другую пару в списке на python - программирование
Подтвердить что ты не робот

Найти другую пару в списке на python

У меня есть список, и я хочу найти другую пару в списке. Я реализую функцию → 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)]]

Есть ли другой лучший способ сделать это? Я хочу, чтобы улучшить мои функции различны. Размер списка может превышать 100 000.

4b9b3361

Ответ 1

Нулевой способ сделать это

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])

Ответ 2

Векторизованное сравнение

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

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

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

Это работает, беря первую пару каждого подмассива и сравнивая каждую со второй парой. Все подмассивы, для которых выбраны не идентичные записи. Рассматривать,

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

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

Из этого мы хотим те строки, которые не имеют True в каждом столбце. Итак, по этому результату используйте all а затем отрицайте результат.

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

Это дает вам маску, которую вы можете использовать для выбора подмассивов из a.


np.logical_or.reduce

Подобно первому варианту выше, но подходит к этой проблеме с другого конца (см. Закон ДеМорга).

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

Ответ 3

Сравнение времени решения

Когда существует так много разных подходов к проблеме, сравнение времени может действительно помочь разобраться в лучших ответах.

Настроить

Мы используем массив размером (200000, 2, 2) как указал О. В. Винченлай, который находится в диапазоне ожидаемого размера массива.

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


Использование ответа Джо: 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)

Использование Coldspeed первый ответ: vectorised сравнение

%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)

Использование Coldspeed второго ответа: 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)

Использование ответа U9 Forward: фильтры

%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)

Использование ответа aydow: фильтры

%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)


Выводы

Джо подходит с numpy.logical_and, безусловно, быстрее. Как и ожидалось, каждый полноценный подход на основе python становится чрезвычайно коротким для чего-то бесчисленного.

Ответ 4

Попробуйте использовать filter:

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)

Ответ 5

Используя понимание списка в одной строке, мы можем сделать, как показано ниже,

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]]

Ответ 6

Использовать список

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