我有很多组2个字符串。我正在尝试确定这两个字符串中匹配元素的数量。规则是如果字符串共享一个共同的字母,这是一个点,顺序确实很重要,但第一个字符串中的每个字母只能匹配第二个字符串中的一个字母。因此,在字符串'aaaab'
,'acccc'
中,仅授予1
点,因为在第二个字符串中只有一个'a'
匹配。以下是一些例子:
aaabb bbaaa 5
aabbb bbbaa 5
aaabb aabbb 4
aaabb ccaaa 3
aaaaa bbbbb 0
ababa babab 4
aabcc babaf 3
abcde abfgh 2
bacde abdgh 3
希望能够了解它是如何运作的。
这是我能够提出的最有效的代码,但它非常令人费解。我希望有人能想到更好的东西。
def Score(guess, solution):
guess = list(guess)
solution = list(solution)
c = 0
for g in guess:
if g in solution and g != "_":
c += 1
solution[solution.index(g)] = "_"
return c
当然,这不是最好的方法,但我无法解决任何问题。我尝试使用Counter
并执行guess&solution
创建一个算法,但这个算法很有效,但最终变慢了。有人有什么想法吗?
答案 0 :(得分:2)
您可以使用NumPy以矢量化形式完成!
import numpy as np
counts1 = np.bincount(np.array('aaadez', 'c').view(np.uint8), minlength=128)
counts2 = np.bincount(np.array('eeeedddddaa', 'c').view(np.uint8), minlength=128)
np.min((counts1, counts2), axis=0).sum()
counts1看起来像这样:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 3, 0, 0, 1, 1, 0...])
这是一个由ASCII码索引的数组。非零元素位于位置97,100和101,它们是ASCII' a' d' d'和' e。然后我们做成对的min(),然后求和得到得分(在这个例子中,4)。
关于这个解决方案的一些好处是你可以将它应用到你想要的任意数量的字符串而不会降低效率,甚至非常长的字符串也会非常快,因为Python本身没有循环 - 仅在编译的NumPy中代码。
在编辑之前,我有一个使用Pandas和SciPy的类似但更慢和更复杂的解决方案。这是:
import scipy.stats
import numpy as np
import pandas
x1 = scipy.stats.itemfreq(np.array('aaade', 'c').view(np.uint8))
x2 = scipy.stats.itemfreq(np.array('bbacadde', 'c').view(np.uint8))
merged = pandas.merge(pandas.DataFrame(x1), pandas.DataFrame(x2), on=0)
np.sum(np.min(merged.values[:,1:], axis=1))
这给了4.0。前两行将字符串转换为整数数组,并运行itemfreq()来计算每个字符出现的次数。在此示例中,x1为:
arrray([[ 97., 3.],
[ 100., 1.],
[ 101., 1.]])
然后我们在第0列加入两个表,删除另一个不存在的任何字符:
0 1_x 1_y
0 97 3 2
1 100 1 2
2 101 1 1
然后我们只做一个min和sum来得到最终得分(在这种情况下为2 + 1 + 1)。
答案 1 :(得分:1)
只需使用remove()
的{{1}}方法而不是使用list
进行查找,即可获得~10%*的加速速度。
此外,您无需将index()
复制到guess
。
list
*至少这是我在机器上测量的那个
答案 2 :(得分:0)
这是;
list_a = list("aabbb")
list_b = list("bbbaa")
list_c = set(list_b)
counter = 0
for i in list_c:
if i in list_b:
counter = list_a.count(i)
print "counter : %s element : %s" %(counter,i )
我只想展示如何计算常用元素,您可以将代码更改为对计数器结果进行求和。
答案 3 :(得分:0)
这是使用Counter的一个非常简单的解决方案:
def proc(vals):
for s1, s2 in vals:
c1, c2 = Counter(s1), Counter(s2)
same = set(s1) & set(s2)
print s1, s2, sum(min(c1[c], c2[c]) for c in same)
vals
看起来像
vals = [('aaaaa', 'bbbbb'), ...]
答案 4 :(得分:0)
试试这个:
a, b = 'aaabb', 'ccaaa'
dict_a, dict_b = {}, {}
for key in list(a):
dict_a[key] = dict_a.setdefault(key, 0) + 1
for key in list(b):
dict_b[key] = dict_b.setdefault(key, 0) + 1
count = 0
for key, a_val in dict_a.items():
try:
b_val = dict_b[key]
count += min(b_val, a_val)
except KeyError:
None
print count
答案 5 :(得分:0)
与@sloth相同的概念,但使用try
代替if
def Score(guess, solution):
solution = list(solution)
c = 0
for g in guess:
try:
solution.remove(g)
c += 1
except ValueError:
pass
return c