比较两个列表并返回不匹配的项目
我有两个列表:
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
就可以了。