比较有关其各自元素后缀的字符串列表
Compare lists of strings regarding the suffixes of their respective elements
假设我有一个这样的列表
myList = ['A_x','B_x','C_x','D_x']
和这样的列表列表
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
现在我想确定 myListOfList
中与 myList
相同的所有列表,除了这些列表中各个元素的后缀,其中 [的子列表中元素的后缀=16=] 必须相同。所以在上面的例子中我想找到:
#all elements as in myList but with suffix y instead of x
['A_y','B_y','C_y','D_y']
#all elements as in myList but with suffix y instead of x but in different order
['A_y','C_y','D_y','B_y']
#all elements as in myList but with suffix z instead of x but in different order
['A_z','C_z','D_z','B_z']
但我不想找到其他的,因为它们的元素没有相同的后缀,长度与 myList's
长度不同,或者元素的第一部分与 [=17] 中的元素不同=].
我是这样实现的:
myList = ['A_x','B_x','C_x','D_x']
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
listOfInd=[]
for ind, sl in enumerate(myListOfList):
if len(sl) == len(myList) and [x.endswith(sl[0][-2:]) for x in sl].count(False) == 0:
tempList = zip(myList, sorted(sl))
allTrue = True
for el in tempList:
#print el[0]
if el[0][:-2] != el[1][:-2]:
allTrue = False
if(allTrue):
listOfInd.append(ind)
这确实给了我正确的输出:listOfInd = [1, 6, 7]
.
解释这段代码的两个元素:
这将检查列表 sl
中的所有元素是否具有相同的后缀:
[x.endswith(sl[0][-2:]) for x in sl].count(False) == 0
这将检查字符串 el
除了后缀(字符串的最后两个元素)之外是否相同:
if el[0][:-2] != el[1][:-2]
所以我要做的是遍历[=16=]中的每个列表,如果这个列表中的元素数量与myList
中的相同并且这个列表中的所有元素都具有相同的后缀,我zip
这个榜单跟myList
。然后我遍历这个压缩列表中的每个元素并比较字符串直到后缀。
该代码有效,但是,它看起来非常低效,我想知道是否有更多 "pythonic" 方法可以在没有这么多循环的情况下执行此操作。谁能想到一种更有效的实现方式?
这是我使用集合的尝试。请注意,我使用的是字符串子索引而不是拆分“_”或正则表达式,因为我假设的格式非常严格。
myList = ['A_x','B_x','C_x','D_x']
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
myList_prefixes = set((x[0] for x in myList))
listOfInd = []
for idx, sublist in enumerate(myListOfList):
if len(sublist) != len(myList):
continue
sublist_suffixes = set((x[-1] for x in sublist))
# ensure that you only have one kind of suffix, like only x or only y
if len(sublist_suffixes) != 1:
continue
sublist_prefixes = set((x[0] for x in sublist))
# make sure the prefixes match
if sublist_prefixes != myList_prefixes:
continue
listOfInd.append(idx)
print listOfInd
如果前缀集,检查前缀集是否是子列表中每个元素的前缀的子集,如果是则检查所有后缀是否相同。
st = {s[0] for s in myList}
l = []
for ind, sub in enumerate(myListOfList):
k = sub[0][-1]
if st.issubset(ch[0] for ch in sub) and all((ch[-1] == k for ch in sub)):
l.append(ind)
print(l)
[1, 6, 7]
如果您愿意,可以将其放在列表中:
inds = [ind for ind, sub in enumerate(myListOfList) if st.issubset(ch[0] for ch in sub)
and all(ch[-1] == sub[0][-1] for ch in sub)]
print(inds)
[1, 6, 7]
您还可以进行一些优化,如果任何子项的长度不等于 myList 的长度,我们将无法匹配:,这样我们就可以使用 all 来查看每个元素[0]是否来自每个sub 在集合中,因为它可能会快一点。
l = []
ln_m = len(myList)
for ind, sub in enumerate(myListOfList):
k = sub[0][-1]
if len(sub) == ln_m and all(ch[0] in st for ch in sub) and all(ch[-1] == k for ch in sub):
l.append(ind)
def compare(l1,l2):
def normalize(l):
r = defaultdict(set)
for a,b in map(lambda x: x.split('_'), l): r[b].add(a)
return set(tuple(sorted(v)) for v in r.values())
n1,n2 = normalize(l1),normalize(l2)
return len(n1)==1 and len(n2)==1 and n1==n2
测试:
>>> [i for i,l in enumerate(myListOfList) if compare(myList,l)]
[1, 6, 7]
关于 compare() 函数内的 normalize() 函数的一点评论:它将为每个后缀生成一组排序的前缀:
>>> normalize(myList)
{('A', 'B', 'C', 'D')}
>>> normalize(['A_x','B_x','C_x','D_y'])
{('A', 'B', 'C'), ('D',)}
>>> normalize(['A_x','B_y','C_z','D_x'])
{('A', 'D'), ('B',), ('C',)}
事实上,如果您删除 len(n1)==1 and len(n2)==1
条件,您可以像我对您的问题的评论那样比较列表。
假设我有一个这样的列表
myList = ['A_x','B_x','C_x','D_x']
和这样的列表列表
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
现在我想确定 myListOfList
中与 myList
相同的所有列表,除了这些列表中各个元素的后缀,其中 [的子列表中元素的后缀=16=] 必须相同。所以在上面的例子中我想找到:
#all elements as in myList but with suffix y instead of x
['A_y','B_y','C_y','D_y']
#all elements as in myList but with suffix y instead of x but in different order
['A_y','C_y','D_y','B_y']
#all elements as in myList but with suffix z instead of x but in different order
['A_z','C_z','D_z','B_z']
但我不想找到其他的,因为它们的元素没有相同的后缀,长度与 myList's
长度不同,或者元素的第一部分与 [=17] 中的元素不同=].
我是这样实现的:
myList = ['A_x','B_x','C_x','D_x']
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
listOfInd=[]
for ind, sl in enumerate(myListOfList):
if len(sl) == len(myList) and [x.endswith(sl[0][-2:]) for x in sl].count(False) == 0:
tempList = zip(myList, sorted(sl))
allTrue = True
for el in tempList:
#print el[0]
if el[0][:-2] != el[1][:-2]:
allTrue = False
if(allTrue):
listOfInd.append(ind)
这确实给了我正确的输出:listOfInd = [1, 6, 7]
.
解释这段代码的两个元素:
这将检查列表 sl
中的所有元素是否具有相同的后缀:
[x.endswith(sl[0][-2:]) for x in sl].count(False) == 0
这将检查字符串 el
除了后缀(字符串的最后两个元素)之外是否相同:
if el[0][:-2] != el[1][:-2]
所以我要做的是遍历[=16=]中的每个列表,如果这个列表中的元素数量与myList
中的相同并且这个列表中的所有元素都具有相同的后缀,我zip
这个榜单跟myList
。然后我遍历这个压缩列表中的每个元素并比较字符串直到后缀。
该代码有效,但是,它看起来非常低效,我想知道是否有更多 "pythonic" 方法可以在没有这么多循环的情况下执行此操作。谁能想到一种更有效的实现方式?
这是我使用集合的尝试。请注意,我使用的是字符串子索引而不是拆分“_”或正则表达式,因为我假设的格式非常严格。
myList = ['A_x','B_x','C_x','D_x']
myListOfList = [['A_x','B_y','C_x','D_z'],
['A_y','B_y','C_y','D_y'],
['A_u','B_y','C_y','D_y'],
['A_y','C_y','B_y','D_y', 'E_l'],
['A_y','P_y','T_y','D_y'],
['A_y','B_y','C_y'],
['A_y','C_y','D_y','B_y'],
['A_z','C_z','D_z','B_z']]
myList_prefixes = set((x[0] for x in myList))
listOfInd = []
for idx, sublist in enumerate(myListOfList):
if len(sublist) != len(myList):
continue
sublist_suffixes = set((x[-1] for x in sublist))
# ensure that you only have one kind of suffix, like only x or only y
if len(sublist_suffixes) != 1:
continue
sublist_prefixes = set((x[0] for x in sublist))
# make sure the prefixes match
if sublist_prefixes != myList_prefixes:
continue
listOfInd.append(idx)
print listOfInd
如果前缀集,检查前缀集是否是子列表中每个元素的前缀的子集,如果是则检查所有后缀是否相同。
st = {s[0] for s in myList}
l = []
for ind, sub in enumerate(myListOfList):
k = sub[0][-1]
if st.issubset(ch[0] for ch in sub) and all((ch[-1] == k for ch in sub)):
l.append(ind)
print(l)
[1, 6, 7]
如果您愿意,可以将其放在列表中:
inds = [ind for ind, sub in enumerate(myListOfList) if st.issubset(ch[0] for ch in sub)
and all(ch[-1] == sub[0][-1] for ch in sub)]
print(inds)
[1, 6, 7]
您还可以进行一些优化,如果任何子项的长度不等于 myList 的长度,我们将无法匹配:,这样我们就可以使用 all 来查看每个元素[0]是否来自每个sub 在集合中,因为它可能会快一点。
l = []
ln_m = len(myList)
for ind, sub in enumerate(myListOfList):
k = sub[0][-1]
if len(sub) == ln_m and all(ch[0] in st for ch in sub) and all(ch[-1] == k for ch in sub):
l.append(ind)
def compare(l1,l2):
def normalize(l):
r = defaultdict(set)
for a,b in map(lambda x: x.split('_'), l): r[b].add(a)
return set(tuple(sorted(v)) for v in r.values())
n1,n2 = normalize(l1),normalize(l2)
return len(n1)==1 and len(n2)==1 and n1==n2
测试:
>>> [i for i,l in enumerate(myListOfList) if compare(myList,l)]
[1, 6, 7]
关于 compare() 函数内的 normalize() 函数的一点评论:它将为每个后缀生成一组排序的前缀:
>>> normalize(myList)
{('A', 'B', 'C', 'D')}
>>> normalize(['A_x','B_x','C_x','D_y'])
{('A', 'B', 'C'), ('D',)}
>>> normalize(['A_x','B_y','C_z','D_x'])
{('A', 'D'), ('B',), ('C',)}
事实上,如果您删除 len(n1)==1 and len(n2)==1
条件,您可以像我对您的问题的评论那样比较列表。