我试图从字符串列表生成所有排列,其中删除某些字符串。我列出了某些化学成分,我希望从该列表中得到所有成分,其中一个元素被删除。此列表的简短摘录如下所示:
AlCrHfMoNbN
AlCrHfMoTaN
AlCrHfMoTiN
AlCrHfMoVN
AlCrHfMoWN
...
我想要得到的是
AlCrHfMoNbN --> CrHfMoNbN
AlHfMoNbN
AlCrMoNbN
AlCrHfNbN
AlCrHfMoN
AlCrHfMoTaN --> CrHfMoTaN
AlHfMoTaN
AlCrMoTaN
AlCrHfTaN
AlCrHfMoN
对于每种成分。我只需要正确的专栏。正如您所看到的,一些最终的成分是重复的,这是预期的。需要删除的元素列表是
Al, Cr, Hf, Mo, Nb, Ta, Ti, V, W, Zr
如你所见,有些长度有两个字符,有些只有一个。
有一个问题是关于非常相似的问题,但我的问题更复杂:Getting a list of strings with character removed in permutation
我尝试根据自己的需要调整代码:
def f(s, c, start):
i = s.find(c, start)
return [s] if i < 0 else f(s, c, i+1) + f(s[:i]+s[i+1:], c, i)
s = 'AlCrHfMoNbN'
print(f(s, 'Al', 0))
但这种简单的方法只会导致['AlCrHfMoNbN', 'lCrHfMoNbN']
。因此,只删除了一个字符,而我需要删除具有不同长度的已定义字符串。此外,我只限于一个输入对象s
- 而不是我需要处理的数百个 - 所以手动循环不是一种选择。
总结我需要的是代码的变化,允许:
由于我只有一些Python和Bash的经验,所以我非常喜欢这些语言的解决方案。
如果你有gawk,请将FPAT设置为[A-Z][a-z]*
,这样每个元素都将被视为一个字段,并使用一个简单的循环来生成排列。还将OFS设置为空字符串,因此输出记录中不会有空格。
$ gawk 'BEGIN{FPAT="[A-Z][a-z]*";OFS=""} {for(i=1;i<NF;++i){p=$i;$i="";print;$i=p}}' file
CrHfMoNbN
AlHfMoNbN
AlCrMoNbN
AlCrHfNbN
AlCrHfMoN
CrHfMoTaN
AlHfMoTaN
AlCrMoTaN
AlCrHfTaN
AlCrHfMoN
CrHfMoTiN
AlHfMoTiN
AlCrMoTiN
AlCrHfTiN
AlCrHfMoN
CrHfMoVN
AlHfMoVN
AlCrMoVN
AlCrHfVN
AlCrHfMoN
CrHfMoWN
AlHfMoWN
AlCrMoWN
AlCrHfWN
AlCrHfMoN
我还写了一个带有额外空格和解释性注释的便携式文件:
awk '{
# separate last element from others
sub(/[A-Z][a-z]*$/, " &")
# from the beginning of line
# we will match each element and print a line where it is omitted
for (i=0; match(substr($1,i), /[A-Z][a-z]*/); i+=RLENGTH)
print substr($1,1,i) substr($1,i+RLENGTH+1) $2
# ^ before match ^ after match ^ last element
}' file
IIUC,你需要的只是str.replace
:
input_list = ['AlCrHfMoNbN', 'AlCrHfMoTaN']
removals = ['Al', 'Cr', 'Hf', 'Mo', 'Nb', 'Ta', 'Ti', 'V', 'W', 'Zr']
result = {}
for i in input_list:
result[i] = [i.replace(r,'') for r in removals if r in i]
输出:
{'AlCrHfMoNbN': ['CrHfMoNbN',
'AlHfMoNbN',
'AlCrMoNbN',
'AlCrHfNbN',
'AlCrHfMoN'],
'AlCrHfMoTaN': ['CrHfMoTaN',
'AlHfMoTaN',
'AlCrMoTaN',
'AlCrHfTaN',
'AlCrHfMoN']}
这不会使用您的尝试,但是当我们假设您的元素始终以大写字母开头(并且只包含小写字母)时,它会起作用:
def f(s):
# split string by elements
import re
elements = re.findall('[A-Z][^A-Z]*', s)
# make a list of strings, where the first string has the first element removed, the second string the second, ...
r = []
for i in range(len(elements)):
r.append(''.join(elements[:i]+elements[i+1:]))
# return this list
return r
当然,这仍然只适用于一个字符串。因此,如果您有一个字符串列表l并且您希望将其应用于其中的每个字符串,只需使用类似的for循环:
# your list of strings
l = ["AlCrHfMoNbN", "AlCrHfMoTaN", "AlCrHfMoTiN", "AlCrHfMoVN", "AlCrHfMoWN"]
# iterate through your input list
for s in l:
# call above function
r = f(s)
# print out the result if you want to
[print(i) for i in r]