按匹配集分组项目

时间:2011-09-21 08:23:52

标签: python

我正在尝试解析大量配置文件,并根据内容将结果分组到不同的组中 - 我只是不知道如何处理这个问题。例如,假设我在3个文件中有以下数据:

config1.txt
ntp 1.1.1.1
ntp 2.2.2.2

config2.txt
ntp 1.1.1.1

config3.txt
ntp 2.2.2.2
ntp 1.1.1.1

config4.txt
ntp 2.2.2.2
The results would be:
Sets of unique data 3:
Set 1 (1.1.1.1, 2.2.2.2): config1.txt, config3.txt
Set 2 (1.1.1.1): config2.txt
Set 3 (2.2.2.2): config4.txt

我理解如何对文件目录进行遍历,循环glob结果并一次打开每个文件,并使用正则表达式匹配每一行。我不理解的部分是我如何存储这些结果并将每个文件与一组结果进行比较,即使条目无序,但匹配条目明智。任何帮助将不胜感激。

谢谢!

5 个答案:

答案 0 :(得分:2)

from collections import defaultdict

#Load the data.
paths = ["config1.txt", "config2.txt", "config3.txt", "config4.txt"]
files = {}

for path in paths:
    with open(path) as file:
        for line in file.readlines():
            ... #Get data from files
            files[path] = frozenset(data)

#Example data.
files = {
    "config1.txt": frozenset(["1.1.1.1", "2.2.2.2"]),
    "config2.txt": frozenset(["1.1.1.1"]),
    "config3.txt": frozenset(["2.2.2.2", "1.1.1.1"]),
    "config4.txt": frozenset(["2.2.2.2"]),
}

sets = defaultdict(list)

for key, value in files.items():
    sets[value].append(key)

请注意,您需要使用frozensets,因为它们是不可变的,因此可以用作字典键。由于它们不会改变,这很好。

答案 1 :(得分:2)

filenames = [ r'config1.txt',
              r'config2.txt',
              r'config3.txt',
              r'config4.txt' ]
results = {}
for filename in filenames:
    with open(filename, 'r') as f:
        contents = ( line.split()[1] for line in f )
        key = frozenset(contents)
        results.setdefault(key, []).append(filename)

答案 2 :(得分:2)

这种替代方案比其他方案更冗长,但根据几个因素可能会更有效(请参阅最后的说明)。除非您处理大量具有大量配置项的文件,否则我甚至不会考虑将其用于其他一些建议,但如果性能存在问题,则该算法可能有所帮助。

从配置字符串到文件集的字典开始(称之为c2f,从文件到配置字符串集(f2c)。两者都可以在您对文件进行全局化时构建

要清楚,c2f是一个字典,其中键是字符串,值是文件集。 f2c是一个字典,其中键是文件,值是字符串集。

循环遍历f2c和一个数据项的文件键。使用c2f查找包含该项目的所有文件。这些是您需要比较的唯一文件。

这是工作代码:

# this structure simulates the files system and contents.
cfg_data = {
    "config1.txt": ["1.1.1.1", "2.2.2.2"],
    "config2.txt": ["1.1.1.1"],
    "config3.txt": ["2.2.2.2", "1.1.1.1"],
    "config4.txt": ["2.2.2.2"]
}

# Build the dictionaries (this is O(n) over the lines of configuration data)
f2c = dict()
c2f = dict()

for file, data in cfg_data.iteritems():
    data_set = set()
    for item in data:
        data_set.add(item)
        if not item in c2f:
            c2f[item] = set()

        c2f[item].add(file)
    f2c[file] = data_set;

# build the results as a list of pairs of lists:
results = []

# track the processed files
processed = set()

for file, data in f2c.iteritems():
    if file in processed:
        continue

    size = len(data)
    equivalence_list = []

    # get one item from data, preferably the one used by the smallest list of
    # files.
    item = None
    item_files = 0
    for i in data:
        if item == None:
            item = i
            item_files = len(c2f[item])
        elif len(c2f[i]) < item_files:
            item = i
            item_files = len(c2f[i])

    # All files with the same data as f must have at least the first item of
    # data, just look at those files.
    for other_file in c2f[item]:
        other_data = f2c[other_file]
        if other_data == data:
            equivalence_list.append(other_file)
            # No need to visit these files again
            processed.add(other_file)

    results.append((data, equivalence_list))

# Display the results
for data, files in results:
    print data, ':', files

添加关于计算复杂性的注释:这在技术上是O((K log N)*(L log M))其中N是文件数,M是唯一配置项的数量K(&lt; = N )是具有相同内容的文件的的数量,并且L(&lt; = M)是对于每个L个处理文件必须成对比较的文件的平均数量。如果K <&lt;&lt; N和L&lt;&lt;微米。

答案 3 :(得分:1)

我会这样做:

首先,得到一个这样的字典:

{(1.1.1.1) : (file1, file2, file3), (2.2.2.2) : (file1, file3, file4) }

然后循环生成集合的文件:

{(file1) : ((1.1.1.1), (2.2.2.2)), etc }

比较集合的值。

if val(file1) == val(file3):
    Set1 = {(1.1.1.1), (2.2.2.2) : (file1, file2), etc }

这可能不是最快和最优雅的解决方案,但它应该有效。

答案 4 :(得分:1)

您需要一个将文件内容映射到文件名的字典。所以你必须阅读每个文件, 对条目进行排序,从中构建一个元组并将其用作密钥。

如果文件中有重复条目:首先将内容读入set