Python |删除数组中的镜像对

时间:2017-05-18 01:27:45

标签: python arrays numpy

在python中,我有一个形状为n * 2的数组(其中n是一个正整数)。从本质上讲,这是一对数组。我希望删除此数组中的所有镜像对。例如,以下数组 A 的形状为 10 * 2 [0,55] [55,0] 对将构成A中的一个镜像对,我希望保留一个那两个。

A = np.array([[ 0, 55], [ 5, 25], [12, 62], [27,  32], [25, 73], 
              [55, 0], [25, 5], [62, 12], [32, 27], [99, 95]])

对于上述示例,我希望结果数组看起来像:

B = np.array([[ 0, 55], [ 5, 25], [12, 62], [27,  32], [25, 73], [99,95])

因为有6个独特的对(在排除4个镜像对之后)。

我意识到我可以使用两个嵌套的for循环来实现这一点,但我希望使用尽可能快的方法来实现这一点,因为对于手头的实际问题,我将处理巨大的问题阵列。我很感激能得到一些帮助。

4 个答案:

答案 0 :(得分:6)

一个神秘的单行:

In [301]: A
Out[301]: 
array([[ 0, 55],
       [ 5, 25],
       [12, 62],
       [27, 32],
       [25, 73],
       [55,  0],
       [25,  5],
       [62, 12],
       [32, 27],
       [99, 95]])

In [302]: np.unique(np.sort(A, axis=1).view(','.join([A.dtype.char]*2))).view(A.dtype).reshape(-1, 2)
Out[302]: 
array([[ 0, 55],
       [ 5, 25],
       [12, 62],
       [25, 73],
       [27, 32],
       [95, 99]])

将其细分为步骤......

首先,创建一个沿第二个轴排序的副本。在排序数组中,我们要删除重复的行。

In [303]: a = np.sort(A, axis=1)

In [304]: a
Out[304]: 
array([[ 0, 55],
       [ 5, 25],
       [12, 62],
       [27, 32],
       [25, 73],
       [ 0, 55],
       [ 5, 25],
       [12, 62],
       [27, 32],
       [95, 99]])

numpy.unique()可用于查找数组的唯一元素,但它仅适用于一维数据。因此,我们将创建b的一维视图,其中每行成为具有两个字段的单个结构。定义我们想要的新数据类型的一种方法是作为字符串:

In [305]: dt = ','.join([A.dtype.char]*2)

In [306]: dt
Out[306]: 'l,l'

b是一个结构化数组;它是a

的一维视图
In [307]: b = a.view(dt)

In [308]: b
Out[308]: 
array([[( 0, 55)],
       [( 5, 25)],
       [(12, 62)],
       [(27, 32)],
       [(25, 73)],
       [( 0, 55)],
       [( 5, 25)],
       [(12, 62)],
       [(27, 32)],
       [(95, 99)]], 
      dtype=[('f0', '<i8'), ('f1', '<i8')])

现在我们使用numpy.unique()查找b的唯一元素:

In [309]: u = np.unique(b)

In [310]: u
Out[310]: 
array([( 0, 55), ( 5, 25), (12, 62), (25, 73), (27, 32), (95, 99)], 
      dtype=[('f0', '<i8'), ('f1', '<i8')])

接下来,使用原始数组u的数据类型创建A的视图。这将是一维的:

In [311]: v = u.view(A.dtype)

In [312]: v
Out[312]: array([ 0, 55,  5, 25, 12, 62, 25, 73, 27, 32, 95, 99])

最后,重塑v以恢复二维数组:

In [313]: w = v.reshape(-1, 2)

In [314]: w
Out[314]: 
array([[ 0, 55],
       [ 5, 25],
       [12, 62],
       [25, 73],
       [27, 32],
       [95, 99]])

答案 1 :(得分:2)

如果您使用的是纯python列表,请尝试以下代码。

>>> list(set([tuple(i) for i in map(sorted, b)]))
[(27, 32), (5, 25), (12, 62), (95, 99), (25, 73), (0, 55)]

答案 2 :(得分:1)

我假设对的顺序并不重要(例如:[1,2] = [2,1])。如果是这种情况,您可以翻转所有对,以便第一个数字始终小于第二个数字。

[[1,2], [4,3], [1,7], [10,2]] 

变为

[[1,2], [3,4], [1,7], [2,10]]

然后你可以按第一个,然后第二个数字排序所有对:

[[1,2], [1,7], [2,10], [3,4]]

最后,您可以遍历列表并删除任何重复对。 如果你使用一个有效的排序算法,比如mergesort,整个过程将有O(n * log(n))工作,这比O(n ^ 2)工作要好得多(嵌套for循环得到的。) / p>

答案 3 :(得分:1)

我会以自己的方式向你展示(因为它有一个我最喜欢的将1D列表转换为nD的技巧),即使可能有更简单的方法:

A = [[ 0, 55], [ 5, 25], [12, 62], [27,  32], [25, 73], 
     [55, 0], [25, 5], [62, 12], [32, 27], [99, 95]]
B=[]

long = int(len(A)/2)

for i in range(long):
  if A[i][0] == A[i+long][1] and A[i][1] == A[i+long][0]:
     B.append(A[i][0])
     B.append(A[i][1])
  else:
     B.append(A[i][0])
     B.append(A[i][1])
     B.append(A[i+long][0])
     B.append(A[i+long][1])
#Now we created an 1D list and then we convert it to 2D!

B=[B[i:i+2] for i in range(0,len(B),2)]