如何仅从数组返回重复项目一次?

时间:2014-08-29 09:14:19

标签: python arrays numpy

我有一个大型数组,其中一部分看起来像这样

...
 [u'3767' u'SS14 3HG']
 [u'3768' u'SS14 3HG']
 [u'3769' u'SS14 3HG']
 [u'3770' u'SS14 3HG']
 [u'3771' u'SS14 3HG']
 [u'3772' u'SS14 3HG']
 [u'4300' u'TA1 4DY']
 [u'4301' u'TA1 4DY']
 [u'4302' u'TA1 4DY']
 [u'4303' u'TA1 4DY']
 [u'4304' u'TA1 4DY']
 ...

如您所见,第二列中的项目重复多次。我需要能够只获得每个重复项目的单个实例及其相应的数字(从第1列开始)。例如:

#output
[u'3767' u'SS14 3HG']
[u'4300' u'TA1 4DY']

我最初认为我可以创建一个for循环,检查当前项是否与下一项相同,如果是,则返回该项并删除下一项。但是,

a)我会得到一个“索引越界”错误和

b)这不是很贵吗?

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

如果它们已经组合在一起,您可以使用itertools.groupby

from itertools import groupby
[next(v) for g,v in groupby(your_list, lambda x:x[1])]

例如:

>>> your_list = [[u'3767', 'SS14 3HG'],
...  [u'3768', 'SS14 3HG'],
...  [u'3769', 'SS14 3HG'],
...  [u'3770', 'SS14 3HG'],
...  [u'3771', 'SS14 3HG'],
...  [u'3772', 'SS14 3HG'],
...  [u'4300', 'TA1 4DY'],
...  [u'4301', 'TA1 4DY'],
...  [u'4302', 'TA1 4DY'],
...  [u'4303', 'TA1 4DY'],
...  [u'4304', 'TA1 4DY']]
>>> from itertools import groupby
>>> [next(v) for g,v in groupby(your_list, lambda x:x[1])]
[[u'3767', 'SS14 3HG'], [u'4300', 'TA1 4DY']]

如果它们没有分组,因为您不关心从第一列中选​​择哪个项目,您可以通过dict运行项目:

>>> [[v,k] for k,v in {k:v for v,k in your_list}.items()]
[[u'4304', 'TA1 4DY'], [u'3772', 'SS14 3HG']]

答案 1 :(得分:2)

您可以使用np.unique获取数组第二列中第一次出现的条目的索引:

>>> indexes = np.unique(myarr[:,1], return_index=True)
(array([u'SS14 3HG', u'TA1 4DY'], 
  dtype='<U8'), array([0, 6]))

返回一个元组:myarr的唯一条目数组以及该条目第一次出现的索引数组。

然后,您可以使用这些索引返回myarr的相关行:

>>> myarr[indexes[1]]
array([[u'3767', u'SS14 3HG'],
       [u'4300', u'TA1 4DY']], 
      dtype='<U8')

答案 2 :(得分:0)

如果性能是您的主要关注点,并且项目已经分组,那么有一个简单快速的numpy解决方案:

import numpy as np

data = np.array([
 [u'3767', u'SS14 3HG'],
 [u'3768', u'SS14 3HG'],
 [u'3769', u'SS14 3HG'],
 [u'3770', u'SS14 3HG'],
 [u'3771', u'SS14 3HG'],
 [u'3772', u'SS14 3HG'],
 [u'4300', u'TA1 4DY'],
 [u'4301', u'TA1 4DY'],
 [u'4302', u'TA1 4DY'],
 [u'4303', u'TA1 4DY'],
 [u'4304', u'TA1 4DY'],
])

items, groups = data.T
flags = np.concatenate(([True], groups[1:]!=groups[:-1]))

print items[flags,0]

如果确实你不需要它,那么就可以通过这种方式避免在np.unique内部执行的排序。

或者,如果您下载代码here,则可以写:

group_by(groups).first(items)

与np.unique解决方案具有相同的特性,但在语法上更清晰。