簡體   English   中英

確定一個字符串是否在其他兩個字符串之間按字母順序排列

[英]Determining whether a string is between two other strings alphabetically

我有2個清單。 第一個只是字符串列表。 第二個是字符串元組的列表。 假設我有s一個列表中的字符串。 我想在第二個列表中找到所有對,其中s在字母順序之間。 一個具體的例子:

s = "QZ123DEF"

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

我想到了一種蠻力方法,即檢查s是否大於第二個列表中的所有元組的第一個字符串,並且小於第二個字符串,但是我想知道是否有更好的方法。 順便說一句,我正在使用python。

這是使用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                                                                                
def between((tupa,tupb),val):
    return tupa <= val <= tupb

s = "QZ123DEF"
print filter(lambda tup:between(tup,s),my_list_tuples)

也許...但是它仍然是“蠻力”

因此,假設元組中只有兩個條目,那么您可以做一點理解:

>>> 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]}

我不知道這是否是蠻力,但以下代碼有效:

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

如果對的數量很大並且搜索的數量也很大,則以下算法可能是有利的。 (我很遺憾沒有時間進行任何比較。)

該算法將第二個列表中的所有字符串復制到一個表中,其中的條目是:a)一個字符串,和b)到原始列表的索引,但是對每個“第二個”字符串都為負(“標記”)然后,對該表進行排序根據第二個列表中的字符串部分。

然后,對於第二個列表中的字符串s,在strpos中找到其字符串大於或等於s的最小條目。

最后,收集從該條目到表末尾的所有索引,記住正索引並跳過負索引。 這將為您提供所有包含字符串s的對。

轉儲strpos表:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM