2

我有一个二维数字列表,两个维度的长度都不同。这些代表主机的开放端口。下面是一个列表,显示了 4 个不同主机上的开放端口:

ports = [[22,23],[22],[22,23,80],[23,80]]

我想计算两个或多个主机共享的所有唯一端口组合,在这个例子中我应该得到以下结果:

Ports -> Count
22     -> 3
22, 23 -> 2
23     -> 3
23, 80 -> 2
80     -> 2

我已经实现了一个解决方案,但我的结果不正确,因为我对给定组合的计数往往超过我正在使用的主机数量,为简洁起见,我没有发布我很长的解决方案,但会用伪代码概述它:

  • 在每个主机之间创建一个交集矩阵

  • 提取/展平矩阵以仅包含唯一集,即不包含相反的顺序。

    -- a AND b, b AND a => a AND b
    
  • 创建一个新列表,其中包含(提取/展平)列表中的每组唯一端口以及该组发生的次数。
4

1 回答 1

5

使用来自itertoolspowerset的配方:

from collections import Counter
from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def port_table(ports):
    d = Counter()
    for portseq in ports:
        for subset in powerset(sorted(portseq)):
            if subset:
                d[subset] += 1
    return d

基本上,powerset给出要递增的所有可能子集(包括空的子集,因此if subset:跳过它),然后对于我们在每个端口列表中看到的每个子集,我们递增一个Counter对象。然后产生

>>> ports = [[22,23],[22],[22,23,80],[23,80]]
>>> table = port_table(ports)
>>> for port, count in sorted(table.items()):
...     if count > 1:
...         print port, '->', count
... 
(22,) -> 3
(22, 23) -> 2
(23,) -> 3
(23, 80) -> 2
(80,) -> 2
于 2012-10-05T12:39:06.150 回答