统一字典列表

时间:2015-01-15 11:34:39

标签: python parsing

我在字符串中接收这样的数据:

foo = """Port  Mac Address       group-addr      vlan    ver
         s2p2  0100.5e00.0004    239.0.0.4       1       1
         s2p0  0100.5e00.0005    239.0.0.8       1       1
         s2p1  0100.5e00.0004    239.0.0.4       1       1"""

我希望将其格式化为表格。当数据进入表格时,我想要每个单独的一行,除非后者4是相同的(mac,group,vlan,ver)。如果发生这种情况,我希望数据在一行上并打印彼此旁边的两个端口

Vlan      Group       Type   Version     Port List
-----------------------------------------------------------------------
1         239.0.0.4   igmp   v1          s2p1, s2p2
1         239.0.0.8   igmp   v1          s2p0

我将数据解析为字典列表:

def parse_lines(lines):
  headers = lines[0].split()
  entries = []
  for r in lines[1:]:
    if not len(r): continue    # skip blank lines
    vals = r.split()
    e = dict(zip(headers,vals))
    entries.append(e)
  return entries

def print_table():
    print "%s %10s %10s %14s %15s" % ("Vlan", "Group", "Type", "Version", "Port List")
    print "---------------------------------------------------------"
    if foo is not None:
        entries = foo.replace("Mac Address", "Mac-Address")    
        entries = parse_lines(entries.split("\n"))

这给我留下了一个字典列表,这是一个格式的例子:

[{'group-addr': '239.0.0.4', 'vlan': '1', 'ver': '1', 'Port': 's2p1', 'Mac-Address': '0100.5e00.0004'}, {'group-addr': '239.0.0.5', 'vlan': '1', 'ver': '1', 'Port': 's2p1', 'Mac-Address': '0100.5e00.0005'}]

在打印之前,我应该如何处理这些以进行比较和存储? 创建一个新词典?比较整个前一个字典的等价的非端口值,然后如果它们都是相同的测试端口并将值添加到新字典中?

5 个答案:

答案 0 :(得分:2)

如果我理解正确,您可以执行以下操作。

对于您收到的每一行,获取除端口之外的所有值,并将它们作为元组中的元组键添加。

('239.0.0.4','0100.5e00.0004', '1', '1') = (group-addr, Mac-Address, vlan, ver)

当然,您可以选择最喜欢的订单,保留

与元组键关联的值是设置端口。

最后,您将拥有许多键值对。把所有这些都放在字典里。

因此字典将如下所示:

{(group-addr, Mac-Address, vlan, ver): set(port1, port2), ...}

要添加新元素,您可以执行以下操作:

try:
    dict[(group-addr, Mac-Address, vlan, ver)].add(port)
except KeyError:
    dict[(group-addr, Mac-Address, vlan, ver)] = set(port)

我现在无法测试它,但我希望你能得到逻辑。

答案 1 :(得分:2)

使用Mac地址,group-addr,vlan和ver作为组合常用元素的键,您应该在最初创建dict时执行此操作,但这是使用您问题中的数据的示例:

foo = """Port  Mac Address       group-addr      vlan    ver
         s2p2  0100.5e00.0004    239.0.0.4       1       1
         s2p0  0100.5e00.0005    239.0.0.8       1       1
         s2p1  0100.5e00.0004    239.0.0.4       1       1"""

from collections import defaultdict
d = defaultdict(set)
lines = foo.splitlines()

for line in lines[1:]:
    prt,mc,gp,vl,vr = line.split()
    d[(mc,gp,vl,vr)].add(prt)
print(d)
defaultdict(<type 'set'>, {('0100.5e00.0004', '239.0.0.4', '1', '1'): set(['s2p2', 's2p1']), ('0100.5e00.0005', '239.0.0.8', '1', '1'): set(['s2p0'])})


print "%s %10s  %14s %15s" % ("Vlan", "Group", "Version", "Port List")
print "---------------------------------------------------------"
for mc, gp, vl, vr in d:
    print("{:<10} {:<14} {:<15}".format(vl,gp,vr)) +",".join(d[mc, gp, vl, v])

Vlan      Group         Version       Port List
---------------------------------------------------------
1          239.0.0.4      1              s2p2,s2p1
1          239.0.0.8      1              s2p0

答案 2 :(得分:1)

一个非常天真的解决方案:

from collections import defaultdict
def group_entries(entries):
    grouped = defaultdict(list)
    for entry in entries:
        port = entry.pop("Port")
        key = tuple(entry.items())
        grouped[key].append(port)
    results = []
    for entry, ports in grouped.items():
        entry = dict(entry)
        entry["ports"] = ", ".join(ports)
        results.append(entry)
    return results


def print_table():
    print "%s %10s %10s %14s %15s" % ("Vlan", "Group", "Type", "Version", "Port List")
    print "---------------------------------------------------------"
    if foo is not None:
        entries = foo.replace("Mac Address", "Mac-Address")    
        entries = parse_lines(entries.split("\n"))
        entries = group_entries(entries)
        # etc

但是在较大的数据集上这可能效率很低。

答案 3 :(得分:1)

重要的是使用要保持相同的字段(mac,group,vlan和ver)为字典创建元组键。然后,创建一个变量来保存端口。我已经选择了一个列表 - 您可以像其他人建议的那样使用一个集合 - 当您打印到&#34; uniqify&#34;港口。我还没有对输出进行任何格式化 - 只需按照指南进行操作即可。我无法看到&#34;键入&#34;在决赛桌中来自 - 但我确信你可以适应这一点。

此外,您的决赛桌不包含MAC列。如果您不需要每个MAC地址一行,只需将其从字典键中删除

即可
foo = """Port  Mac Address       group-addr      vlan    ver
             s2p2  0100.5e00.0004    239.0.0.4       1       1
             s2p0  0100.5e00.0005    239.0.0.8       1       1
             s2p1  0100.5e00.0004    239.0.0.4       1       1"""

lines = foo.splitlines()
headers = lines[0]

machineDict={}
for line in lines[1:]:
    prt,mac,grp,vl,vr = line.split()
    try:
        #try to add a new port to the entry with this key
        machineDict[(mac,grp,vl,vr)].append(prt)
    except KeyError:
        #key error signals the dictionary doesn't contain that key
        # so create an entry
        machineDict[(mac,grp,vl,vr)] = [prt]

print "%s %10s %10s %14s %15s" % ("Vlan", "Group", "Type", "Version", "Port List")
print "---------------------------------------------------------"
for (mac,grp,vl,vr),portList in machineDict.items():
    print "%s %10s %10s %14s %15s" % (vl,grp,"typeVar",vr,list(set(portList)))

注意list(set(portList))结构只是&#34; unqified&#34;您的机器的端口列表。因为它们在您的输入数据中可能是唯一的 - 如果适合您,可以将其替换为portList

答案 4 :(得分:0)

根据Peter Bengtsson的Fastest way to uniqify a list in Python,两个表现最好的方法结果是将序列转换为一组 - 有序或正常。

那里有一个相当古老的Python版本的代码,所以我不会在这里粘贴它。相反,Does Python have an ordered set?给出了第一个选项的概述(第二个是内置类型)。

要成为集合的成员,您的元素必须是可清除的。所以,你需要例如使用namedtuple而不是字典来存储记录。