比较两个列表并返回不匹配的项目

3 投票
4 回答
3432 浏览
提问于 2025-04-18 11:37

我有两个列表:

nodes = [[nodeID1, x1, y1, z1],[nodeID2, x2, y2, z2],...,[nodeIDn, xn, yn, zn]]

还有一个列表:

subsetA_nodeID = [[nodeIDa], [nodeIDb], ....]]

我想比较这两个列表,返回一个新列表,里面包含那些在nodes中但不在subsetA_nodeID中的nodeIDs, x, y, z

我可以这样做:

new_list = []
for line in nodes:
   for nodeID,x,y,z in line:
      for line2 in subsetA_nodeID:
         if line2[0] == nodeID:
         else:
            new_list.append([line])

不过这段代码效率太低了。我想找一个更快的方法来实现这个功能。我试过用字典,但不知道怎么正确使用。有没有什么好的建议?

谢谢!

4 个回答

2

你可以试着用列表推导式来查看它们全部:

new_list = [node for node in nodes if node[0] not in subsetA_nodeID]

不过我不太确定这样做的效率和其他答案相比如何。正如另一个答案所说,你可能需要把你的 subsetA_nodeID 转换成一维列表,这样才能让它正常工作。

2

对于这种情况,numpy是你的好帮手...

import itertools,numpy

a = numpy.array(nodes)
list_of_ids = itertools.chain(*subsetA_nodeID) # flatten
mask = ~numpy.in1d(a[:,1],list_of_ids) # intersection negated
print a[mask] # show the rows that match this condition

我还建议把 list_of_ids 变成一个集合,因为查找集合里的东西要快得多(numpy可能在背后已经这样做了...我不太确定)

2

对于大问题来说,逐个处理整个内容可能不是个好主意。除了@JoranBeasley的建议,pandas也是一个不错的选择:

In [52]:
import pandas as pd
nodes = [['nodeID1', 'x1', 'y1', 'z1'],['nodeID2', 'x2', 'y2', 'z2'],['nodeIDn', 'xn', 'yn', 'zn']]
subsetA_nodeID = [['nodeID1'], ['nodeID2']]
subsetA_nodeIDa = ['nodeID1', 'nodeID2'] #use itertools.chain to get this
In [53]:

df=pd.DataFrame(nodes)
print df
df.set_index(0, inplace=True)
print df
         0   1   2   3
0  nodeID1  x1  y1  z1
1  nodeID2  x2  y2  z2
2  nodeIDn  xn  yn  zn
          1   2   3
0                  
nodeID1  x1  y1  z1
nodeID2  x2  y2  z2
nodeIDn  xn  yn  zn
In [54]:

print df.ix[subsetA_nodeIDa]
          1   2   3
nodeID1  x1  y1  z1
nodeID2  x2  y2  z2
In [55]:

list(map(list, df.ix[subsetA_nodeIDa].values))
Out[55]:
[['x1', 'y1', 'z1'], ['x2', 'y2', 'z2']]
3

我建议先把 subsetA_nodeID 变成一维的,也就是“扁平化”。

ssa_flat = [x for sublist in subsetA_nodeID for x in sublist] 

或者,如果 subsetA_nodeID 中的每个子列表只包含一个元素的话:

ssa_flat = [x[0] for x in subsetA_nodeID]

如果这些节点是可以被哈希的,可以考虑把 ssa_flat 变成一个 set(集合)。

ssa_flat = set(ssa_flat)

然后你可以这样创建你的新列表:

lst = [x[0] for x in nodes if x[0] not in ssa_flat]

补充说明:如果 lst 应该包含 [NodeID, x, y, z] 这样的列表,只需在最后的列表推导式中把第一个 x[0] 改成 x 就可以了。

撰写回答