我使用WiX XML文件工作很多,而且WiX中的每个对象都需要一个GUID。为了避免复制粘贴错误,我设置了一种方法来排序和显示所有重复的GUID,给定一个这样的列表(使用find
和egrep
创建):
./A2.Spam.EggsMgrSvc/__A2.Spam.EggsMgrSvc.wixproj:3A206536-FBCC-4911-AF2B-CBCD76E2C23E
./A2.Spam.TrojanBunnies/Files/Files.wxs:1F372E8A-95B9-49AC-84A6-998E7F5B0689
./A2.Spam.TrojanBunnies/Files/Files.wxs:4BB4FBAD-032A-4FBA-8B81-8AA2876E6765
./A2.Spam.TrojanBunnies/Files/File1.wxs:E289D834-4421-4DCE-B0A8-94C09978058A
./A2.Spam.TrojanBunnies/Files/Files.wxs:083863F1-70DE-11D0-BD40-00A0C911CE86
./A2.Spam.TrojanBunnies/Files/File1.wxs:E289D834-4421-4DCE-B0A8-94C09978058A
./A2.Spam.TrojanBunnies/Files/Files.wxs:083863F1-70DE-11D0-BD40-00A0C911CE86
./A2.Spam.TrojanBunnies/Files/File2.wxs:E289D834-4421-4DCE-B0A8-94C09978058A
采用以下格式:
3 E289D834-4421-4DCE-B0A8-94C09978058A
2 ./A2.Spam.TrojanBunnies/Files/File1.wxs
1 ./A2.Spam.TrojanBunnies/Files/File2.wxs
2 083863F1-70DE-11D0-BD40-00A0C911CE86
2 ./A2.Spam.TrojanBunnies/Files/Files.wxs
在GUID旁边计算GUID的出现次数,然后在每个文件中计算该GUID的出现次数。
我想出了以下脚本(产生了上面的输出)。我还是Python新手,我真的想了解字典及其实际用途。使用嵌套词典是正确的方法吗?我选择了字典,因为我认为这是添加/跟踪唯一条目的最简单方法。虽然,使用像parent_dict['child_dict_key']['value_key']
这样的语法感觉有点奇怪,但也许我可以使用items()
或其他可迭代的方法/技术:
#!/usr/bin/env python
guids = {}
f_and_g = open( 'files-and-guids.txt', 'r')
for fg in f_and_g.readlines():
fname, guid = map( str.strip, fg.split(':') )
if guid not in guids:
guids[guid] = { 'count': 1, 'files': {} }
else:
guids[guid]['count'] += 1
## Count how many times a GUID was used in a given file
if fname not in guids[guid]['files']:
guids[guid]['files'][fname] = 1
else:
guids[guid]['files'][fname] += 1
## Sort by total count for a given GUID
for guid in sorted( guids, key=lambda x:guids[x]['count'], reverse=True):
## Skip printing if count is below threshold
if guids[guid]['count'] < 2:
continue
guid_dict = guids[guid]
print '{:>3} {}'.format( guid_dict['count'], guid )
## Sort by filename counts
for fname in sorted( guid_dict['files'],
key=lambda x: guid_dict['files'][x], reverse=True ):
fname_cnt = guid_dict['files'][fname]
print '{:>8} {}'.format( fname_cnt, fname)
答案 0 :(得分:2)
我会这样做,虽然我实际上没有测试过这段代码:
#!/usr/bin/env python
import collections
import operator
guids = collections.defaultdict(collections.Counter)
f_and_g = open('files-and-guids.txt', 'r')
for fg in f_and_g:
fname, guid = map(str.strip, fg.split(':'))
guids[guid][fname] += 1
## Sort by total count for a given GUID
guids_counts_totals = [(guids, counts, sum(counts.itervalues()))
for guids, counts
in guids.iteritems()]
guids_counts_totals_sorted = sorted(guids_counts_totals,
key=operator.itemgetter(2),
reverse=True)
for guid, counts, total in guids_counts_totals_sorted:
## Skip printing if count is below threshold
if total < 2:
continue
print '{:>3} {}'.format(total, guid)
## Sorting by filename counts
fnames_counts_sorted = sorted(counts.iteritems(),
key=operator.itemgetter(1), reverse=True)
for fname, count in fnames_counts_sorted:
print '{:>8} {}'.format(count, fname)
这里有一些变化:
collections.defaultdict
和collections.Counter
代替重复检查是否存在密钥,如果密钥不存在则将其设置为1 dict.itervalues()
进行排序和迭代,而不是仅仅使用键,然后查找其值operator.itemgetter()
代替lambda
表达式答案 1 :(得分:2)
另一种变化:
#!/usr/bin/env python
import fileinput
from collections import defaultdict, Counter
# count guids
perfile = defaultdict(Counter)
total = Counter()
for line in fileinput.input():
fname, guid = map(str.strip, line.split(':'))
perfile[guid][fname] += 1
total[guid] += 1
# print most common guid first
for guid, count in total.most_common():
if count < 2: continue # skip printing if count is below threshold
print '{:>3} {}'.format(count, guid)
# sorting by filename counts
for fname, fname_cnt in perfile[guid].most_common():
print '{:>8} {}'.format(fname_cnt, fname)
$ python2.7 count-guid.py input
3 E289D834-4421-4DCE-B0A8-94C09978058A
2 ./A2.Spam.TrojanBunnies/Files/File1.wxs
1 ./A2.Spam.TrojanBunnies/Files/File2.wxs
2 083863F1-70DE-11D0-BD40-00A0C911CE86
2 ./A2.Spam.TrojanBunnies/Files/Files.wxs
如果脚本清晰并且适用于你,请不要过度思考。
答案 2 :(得分:0)
基于我再次尝试的一些答案,为了让我的生活更加困难而避开任何其他的lib:
def MyCounter(l):
d = dict()
for i in l:
if i not in d:
d[i] = 1
else:
d[i] += 1
return d
def main():
guids = dict()
f_and_g = open('files-and-guids.txt', 'r')
for fg in f_and_g.readlines():
fname, guid = map(str.strip, fg.split(':'))
if guid not in guids:
guids[guid] = [fname]
else:
guids[guid] += [fname]
## Sort by total count for a given GUID
for guid in sorted(guids, key=lambda guid: len(guids[guid]), reverse=True):
## Skip printing if count is below threshold
if len(guids[guid]) < 2: continue
guid_list = guids[guid]
print '{:>3} {}'.format( len(guid_list), guid )
## Sort by filename counts
counts = MyCounter(guid_list)
for fname, fname_cnt in sorted(counts.iteritems(), key=lambda x:x[1],
reverse=True):
print '{:>8} {}'.format(fname_cnt, fname)