按字母顺序确定字符串是否在两个其他字符串之间

时间:2014-01-27 21:17:25

标签: python string algorithm sorting

我有2个清单。第一个只是一个字符串列表。第二个是字符串元组列表。假设我在第一个列表中有字符串s。我想找到第二个列表中s按字母顺序排列的所有对。一个具体的例子:

s = "QZ123DEF"

("QZ123ABC", "QZ125ZEQ") # would return as a positive match
("QF12", "QY22") # would not return as a positive match

我想到了一种强力方法,可以检查s是否大于第一个字符串,并且对于第二个列表中的所有元组少于一秒,但我想知道是否存在更好的方法。顺便说一下,我正在使用python。

5 个答案:

答案 0 :(得分:2)

以下是使用bisect模块的一种方法,这需要先排序S

import bisect
import pprint
S = ['b', 'd', 'j', 'n', 's']
pairs = [('a', 'c'), ('a', 'e'), ('a', 'z')]

output = {}

for a, b in pairs:

    # Here `a_ind` and `b_ind` are the indices where `a` and `b` will fit in
    # the list `S`. Using these indices we can find the items from the list that will lie 
    # under `a` and `b`.

    a_ind = bisect.bisect_left(S, a)
    b_ind = bisect.bisect_right(S, b)

    for x in S[a_ind : b_ind]:
        output.setdefault(x, []).append((a, b))

pprint.pprint(output)

<强>输出:

{'b': [('a', 'c'), ('a', 'e'), ('a', 'z')],
 'd': [('a', 'e'), ('a', 'z')],
 'j': [('a', 'z')],
 'n': [('a', 'z')],
 's': [('a', 'z')]}

与随机数据上的强力方法相比,这快2-3倍:

def solve(S, pairs):

    S.sort()
    output = {}
    for a, b in pairs:
        a_ind = bisect.bisect_left(S, a)
        b_ind = bisect.bisect_right(S, b)
        for x in S[a_ind : b_ind]:
            output.setdefault(x, []).append((a, b))

def brute_force(S, pairs):

    output = {}
    for s in S:
        for a, b in pairs:
            if a <= s <= b:
                output.setdefault(s, []).append((a, b))

def get_word():
    return ''.join(random.choice(string.letters))

S = [get_word() for _ in xrange(10000)]
pairs = [sorted((get_word(), get_word())) for _ in xrange(1000)]

时间比较:

In [1]: %timeit brute_force(S, pairs)                                                                              
1 loops, best of 3: 10.2 s per loop                                                                                

In [2]: %timeit solve(S, pairs)                                                                                    
1 loops, best of 3: 3.94 s per loop                                                                                

答案 1 :(得分:1)

def between((tupa,tupb),val):
    return tupa <= val <= tupb

s = "QZ123DEF"
print filter(lambda tup:between(tup,s),my_list_tuples)
也许......但它还是“蛮力”

答案 2 :(得分:1)

假设元组中只有两个条目,你可以做一点理解:

>>> s = "QZ123DEF"
>>> testList = [("QZ123ABC", "QZ125ZEQ"), ("QF12", "QY22")]
>>> [test[0] <= s <= test[1] for test in testList]
[True, False]

这可以针对s列表展开,其结果存储在dict中:

>>> S = ["QZ123DEF", "QG42"]
>>> {s: [test[0] <= s <= test[1] for test in testList] for s in S}
{'QZ123DEF': [True, False], 'QG42': [False, True]}

答案 3 :(得分:0)

我不知道这是否是一种蛮力但是代码有效:

def foo(s,a,b):
    if s<=a and s>=b:
        return True
    if s>=a and s<=b:
        return True
    return False


print foo("QZ123DEF", "QZ123ABC", "QZ125ZEQ") --> True
print foo("QZ123DEF", "QF12", "QY22") --> False

答案 4 :(得分:0)

如果对的数量很大并且搜索次数也很多,则以下算法可能是有利的。 (我很遗憾没有时间进行任何比较。)

此算法将第二个列表中的所有字符串复制到表中,其中条目为: a)一个字符串,和 b)原始列表的索引,但每个“第二”字符串为负(“标记”) 然后,根据第二个列表中的字符串组件对此表进行排序。

然后,对于第二个列表中的字符串s,找到strpos中字符串大于或等于s的最小条目。

最后,收集从该条目开始到表格末尾的所有索引,记住正面指数并跳过它们的负面对应物。这将为您提供包含字符串s的所有对。

转储表的转储:

AAA at 1
BBB at 2
CCC at -1
FFF at -2
HHH at 3
LLL at -3
NNN at 4
ZZZ at -4

三个字符串的结果:

for ABC found AAA - CCC
for XYZ found NNN - ZZZ
for IJK found HHH - LLL
for HHH found HHH - LLL