获取列表之间第一个和最后一个公共元素的索引的最快方法

时间:2018-09-11 22:36:59

标签: python list numpy

我有两个排序列表

x = [-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10]
y = [3,4,5,6]

在这两个xy之间,我想返回imin = (6,0)imax = (9,3)。如果这些列表不共享任何元素,我想返回imin = Noneimax = None

解决方案是

def inds(x,y):
    arr = [(i,j) for i,xx in enumerate(x) for j,yy in enumerate(y) if xx==yy ]
    if arr!=[]: # to obtain proper None output
        imin = (min(i for i,_ in arr), min(j for _,j in arr))
        imax = (max(i for i,_ in arr), max(j for _,j in arr))
    else: 
        imin = None
        imax = None 
    return (imin,imax)

这会执行很多不必要的计算(O(n ** 2)),这是我的程序之一的瓶颈。任何人都可以更快地提出建议吗?

附加(非最小示例)信息

如果有帮助,我实际上有一个对象列表。

objects = [(A1,B1),(A2,B2)] 

xy将是该对象列表的每个元素的属性,如下所示:

x = objects[0][0].attrib
y = objects[0][1].attrib

我实际上想生成

[(imin1,imax1),(imin2,imax2)]

例如,哪个可能来自

def attribs(A,B):
    return (A.attrib,B.attrib)

[inds(*attribs(*v)) for v in objects]

注意:我添加了一个numpy标签,只是因为我愿意使用numpy来实现这一点,如果它更快。

3 个答案:

答案 0 :(得分:1)

这应该是你所追求的

c = set(x).intersection(y)  # O(n) time
def get_first(l):
    return next((idx for idx, elm in enumerate(l) if elm in c), None)  # O(n) time
imin = (get_first(x), get_first(y))
imax = (len(x) - get_first(x[::-1]) - 1, len(y) - get_first(y[::-1]) - 1)

从这里开始,您可以进行一些调整,但它仍将运行O(n)

答案 1 :(得分:1)

使用overflow-y:hidden;并返回索引,您可以执行以下操作

np.intersect1d

说明

idxes = np.stack(np.intersect1d(x,y, return_indices=True)[1:]) ix = tuple(idxes[:,0]) iy = tuple(idxes[:,-1]) >>> ix (6, 0) >>> iy (9, 3) 是索引的二维数组,其中两个数组之间有交集:

idxes

因此您可以使用

进行第一个和最后一个
>>> idxes
array([[6, 7, 8, 9],
       [0, 1, 2, 3]])

答案 2 :(得分:1)

您还可以对相交列表进行排序,并使用.index()来查找索引。

z = list(set(x).intersection(set(y))) # O(n)
z.sort() # O(nlogn)

imin = (x.index(z[0]), y.index(z[0])) # O(n)
imax = (x.index(z[-1]), y.index(z[-1])) # O(n)