Python - 在字典中查找重复出现的 pairs/groups 个值
Python - find recurring pairs/groups of values in dictionary
我有以下脚本,它循环遍历 css 规则的文本文件,并将每个规则及其属性存储在字典中(欢迎改进代码,我才刚刚开始使用 Python):
findGroups.py
import sys
source = sys.argv[1]
temp = open('pythonTestFile.txt', 'w+')
di = {}
with open(source, 'r') as infile:
for line in infile:
# if line starts with . or #, contains _ or - between
# words and has a space and opening brace(ie is css rule name)
if re.search('((([\.\-\'])?\w+\s?\{', line):
key = line.replace("{", "")
di[key] = []
line = next(file)
while "}" not in line:
# remove trailing whitespace and \n
line = ' '.join(line.split())
di[key].append(line)
line = next(infile)
temp.close();
source.txt
* {
min-height: 1000px;
overflow: hidden;
}
.leftContainerDiv {
font-family: Helvetica;
font-size: 10px;
background: white;
}
#cs_ht_panel{
font-family:10px;
display:block;
font-family:Helvetica;
width:auto;
}
//...etc
我希望输出看起来像这样(也欢迎提出可读性建议):
pythonTestFile.txt
Group 1, count(2) - font-family: Helvetica; + font-size: 10px;
Group 2: //...etc
我现在想做的是弄清楚哪些 css 属性是重复出现的组,例如,如果 font-size: 10px 和 font-family: Helvetica 在规则中一起出现,这个组是否出现在任何其他规则中以及它出现了多少次。
我不完全确定该去哪里,我什至不知道如何开始某种比较算法,或者字典是否是存储文本的正确数据结构。
编辑:作为对评论的回应,我无法使用第三方库。此脚本将在 Red Hat VM 上使用,并且只能将预先批准的软件推送到这些上,我无法只下载库或软件包
给每个css属性分配一个不同的素数,比如:
{
'diplay: block': 2
'font-size: 10px': 3,
'font-family: Helvetica': 5,
'min-height: 1000px': 7,
'overflow: hidden': 11,
'width: auto': 13,
'background: white': 17,
}
然后做一个字典,其中键是 css 选择器(你称之为 "rules"),值是它具有的所有属性的乘积:
{
'#cs_ht_panel': 390, # 2 * 3 * 5 * 13
'*': 77, # 7 * 11
'.leftContainerDiv': 255, # 3 * 5 * 17
}
现在您可以轻松确定两件事:
- 哪些选择器 ("rules") 具有 属性
x
(由其质数表示)或一组属性 {x,y,z,..}
(由其质数的乘积表示) ) 通过查看选择器编号是否可以被该编号整除。
例如什么选择器同时具有 'font-family: Helvetica'
(5) 和 font-size: 10px
(3)?所有且仅能被 15 整除的那些。
- 通过计算 GCD(最大公约数),两个选择器共有的所有属性。
例如GCD(390, 77) = 1 -> 它们没有共同的属性
GCD(390, 255) = 15 -> 分解 -> 3 * 5
您还可以通过遍历所有选择器值来找到最常见的组,找到所有不是素数的适当除数,并保留一个字典来保存找到该除数的数字。每个除数都是一个群,你可以通过分解它来找到它的元素。
- 390 -> 6 10 15 26 30 39 65 78 130 195
- 255 -> 15 51 85
- 77 ->
所以你有两次 15,其他所有 1 次。也就是说15这个组出现了2次,也就是属性3和5的组
最后一个计算步骤是 2^n,其中 n 是 css 选择器中的属性数。这应该不是问题,因为大多数选择器的属性都少于 10 个,但如果属性超过 20 个,您就会遇到麻烦。我建议通过删除前缀(moz-、webkit-)和后缀(-left、-right、-top、-bottom)来压缩属性
你可以(而且可能应该,对于真正的 CSS 有数百行的文件)只使用集合和它们的操作(交集等)而不是数字、乘积和素数;但这不是更酷吗? ;)
基于上述想法的解决方案 - 我使用的是集合和有序列表,而不是使用质数。也许这就是你想要的?
import re
import itertools
f = open('css_test.txt', 'r')
lines = f.readlines()
lines_str = ' '.join([l.strip() for l in lines])
#print lines_str
r = re.compile(r'.*?{(.*?)}') # Get All strings between {}
groups = r.findall(lines_str)
#print groups
# remove any stray spaces in the string and create groups of attributes like
# style: value
grps = []
for grp in groups:
grps.append(filter(lambda x: len(x) > 0, grp.strip().split(';')))
# clean up those style: value attributes so that we get 'style:value'
# without any spaces and also collect all such attributes (we'd later create
# a set of these attributes)
grps2 = []
all_keys = []
for grp in grps:
grp2 = []
for g in grp:
x = ':'.join([x.strip() for x in g.split(':')])
grp2.append(x)
all_keys.append(x)
grps2.append(grp2)
set_keys = set(sorted(all_keys))
print set_keys
print '***********'
set_dict = {}
# For each combination of 2 of keys in the set find intersection of this
# set with the set of keys in the cleaned up groups above
# if intersection is the set of 2 keys: initialize a dictionary or add 1
for x in itertools.combinations(set_keys, 2):
for g in grps2:
set_x = set(x)
set_g = set(g)
#print "set_g : ", set_g
if set_x & set_g == set_x:
print set_x
if set_dict.has_key(x):
set_dict[x] += 1
else:
set_dict[x] = 1
# print everything
print set_dict
即使此解决方案与您想要的不完全匹配 - 也许您可以按照上述思路得出您想要做的事情?
我有以下脚本,它循环遍历 css 规则的文本文件,并将每个规则及其属性存储在字典中(欢迎改进代码,我才刚刚开始使用 Python):
findGroups.py
import sys
source = sys.argv[1]
temp = open('pythonTestFile.txt', 'w+')
di = {}
with open(source, 'r') as infile:
for line in infile:
# if line starts with . or #, contains _ or - between
# words and has a space and opening brace(ie is css rule name)
if re.search('((([\.\-\'])?\w+\s?\{', line):
key = line.replace("{", "")
di[key] = []
line = next(file)
while "}" not in line:
# remove trailing whitespace and \n
line = ' '.join(line.split())
di[key].append(line)
line = next(infile)
temp.close();
source.txt
* {
min-height: 1000px;
overflow: hidden;
}
.leftContainerDiv {
font-family: Helvetica;
font-size: 10px;
background: white;
}
#cs_ht_panel{
font-family:10px;
display:block;
font-family:Helvetica;
width:auto;
}
//...etc
我希望输出看起来像这样(也欢迎提出可读性建议):
pythonTestFile.txt
Group 1, count(2) - font-family: Helvetica; + font-size: 10px;
Group 2: //...etc
我现在想做的是弄清楚哪些 css 属性是重复出现的组,例如,如果 font-size: 10px 和 font-family: Helvetica 在规则中一起出现,这个组是否出现在任何其他规则中以及它出现了多少次。
我不完全确定该去哪里,我什至不知道如何开始某种比较算法,或者字典是否是存储文本的正确数据结构。
编辑:作为对评论的回应,我无法使用第三方库。此脚本将在 Red Hat VM 上使用,并且只能将预先批准的软件推送到这些上,我无法只下载库或软件包
给每个css属性分配一个不同的素数,比如:
{
'diplay: block': 2
'font-size: 10px': 3,
'font-family: Helvetica': 5,
'min-height: 1000px': 7,
'overflow: hidden': 11,
'width: auto': 13,
'background: white': 17,
}
然后做一个字典,其中键是 css 选择器(你称之为 "rules"),值是它具有的所有属性的乘积:
{
'#cs_ht_panel': 390, # 2 * 3 * 5 * 13
'*': 77, # 7 * 11
'.leftContainerDiv': 255, # 3 * 5 * 17
}
现在您可以轻松确定两件事:
- 哪些选择器 ("rules") 具有 属性
x
(由其质数表示)或一组属性{x,y,z,..}
(由其质数的乘积表示) ) 通过查看选择器编号是否可以被该编号整除。
例如什么选择器同时具有'font-family: Helvetica'
(5) 和font-size: 10px
(3)?所有且仅能被 15 整除的那些。 - 通过计算 GCD(最大公约数),两个选择器共有的所有属性。
例如GCD(390, 77) = 1 -> 它们没有共同的属性
GCD(390, 255) = 15 -> 分解 -> 3 * 5
您还可以通过遍历所有选择器值来找到最常见的组,找到所有不是素数的适当除数,并保留一个字典来保存找到该除数的数字。每个除数都是一个群,你可以通过分解它来找到它的元素。
- 390 -> 6 10 15 26 30 39 65 78 130 195
- 255 -> 15 51 85
- 77 ->
所以你有两次 15,其他所有 1 次。也就是说15这个组出现了2次,也就是属性3和5的组
最后一个计算步骤是 2^n,其中 n 是 css 选择器中的属性数。这应该不是问题,因为大多数选择器的属性都少于 10 个,但如果属性超过 20 个,您就会遇到麻烦。我建议通过删除前缀(moz-、webkit-)和后缀(-left、-right、-top、-bottom)来压缩属性
你可以(而且可能应该,对于真正的 CSS 有数百行的文件)只使用集合和它们的操作(交集等)而不是数字、乘积和素数;但这不是更酷吗? ;)
基于上述想法的解决方案 - 我使用的是集合和有序列表,而不是使用质数。也许这就是你想要的?
import re
import itertools
f = open('css_test.txt', 'r')
lines = f.readlines()
lines_str = ' '.join([l.strip() for l in lines])
#print lines_str
r = re.compile(r'.*?{(.*?)}') # Get All strings between {}
groups = r.findall(lines_str)
#print groups
# remove any stray spaces in the string and create groups of attributes like
# style: value
grps = []
for grp in groups:
grps.append(filter(lambda x: len(x) > 0, grp.strip().split(';')))
# clean up those style: value attributes so that we get 'style:value'
# without any spaces and also collect all such attributes (we'd later create
# a set of these attributes)
grps2 = []
all_keys = []
for grp in grps:
grp2 = []
for g in grp:
x = ':'.join([x.strip() for x in g.split(':')])
grp2.append(x)
all_keys.append(x)
grps2.append(grp2)
set_keys = set(sorted(all_keys))
print set_keys
print '***********'
set_dict = {}
# For each combination of 2 of keys in the set find intersection of this
# set with the set of keys in the cleaned up groups above
# if intersection is the set of 2 keys: initialize a dictionary or add 1
for x in itertools.combinations(set_keys, 2):
for g in grps2:
set_x = set(x)
set_g = set(g)
#print "set_g : ", set_g
if set_x & set_g == set_x:
print set_x
if set_dict.has_key(x):
set_dict[x] += 1
else:
set_dict[x] = 1
# print everything
print set_dict
即使此解决方案与您想要的不完全匹配 - 也许您可以按照上述思路得出您想要做的事情?