【问题标题】:Binary-search + linear-search to find multiple matches. How to return a tuple of results? (Python)二进制搜索 + 线性搜索以查找多个匹配项。如何返回结果元组? (Python)
【发布时间】:2014-08-30 05:15:03
【问题描述】:

我编写了一个搜索算法,它在排序列表中找到一个字符串,然后在两边的条目中搜索重复项。

import re

found = []
missing = []

def find_media(media, drive_inv):
    """
    media is a string.
    drive_inv is a list of strings.
    use binary search to find a match,
    followed by a linear seach either side
    to check for duplicates.
    append a match to the global list, found.
    else append to the global list, missing.
    """

    def linear_search_up(media, line):
        """ line is an int, to index drive_inv with. """

        try:
            if re.search(media, drive_inv[line+1], re.IGNORECASE):
                found.append(drive_inv[line+1])
                return linear_search_up(media, line+1)
            else:
                return 

        except IndexError:
            return 

    def linear_search_down(media, line):
        """ line is an int, to index drive_inv with. """
        try:
            if re.search(media, drive_inv[line-1], re.IGNORECASE):
                found.append(drive_inv[line-1])
                return linear_search_down(media, line-1)
            else:
                return 

        except IndexError:
            return 

    def binary_search(media, low, high):
        """
        low and high are ints - the boundries of the
        binary search algorithm.
        if a match is found, execute the linear seach
        function on the entries either side.
        """

        if high == low:
            if re.search(media, drive_inv[low], re.IGNORECASE):
                found.append(drive_inv[low])
                return
            else:
                missing.append(media)
                return

        mid = (low + high) / 2

        if re.search(media, drive_inv[mid], re.IGNORECASE):
            found.append(drive_inv[mid])

#           now check the entries either side
            return (
                    linear_search_up(media, mid),
                    linear_search_down(media, mid
            )

#       if the filename > media, discard the larger entries
        elif drive_inv[mid].split('/')[-1] > media:
            if low == mid:
                missing.append(media)
                return
            else:
                return binary_search(media, low, mid-1)

#       if the filename < media, discard the smaller entries
        else:
            return binary_search(media, mid+1, high)

    if len(drive_inv) == 0:
        return
    else:
        return binary_search(media, 0, len(drive_inv)-1)

它似乎工作得很好,但它有点难看,将结果附加到全局列表中。我希望它返回所有匹配项的元组。但是,如果我改变:

found.append(drive_inv[line+1])
return linear_search_up(media, line+1)

到:

return (
        drive_inv[line+1],
        linear_search_up(media, line+1)
)

我最终得到一个如下所示的元组:

(('A001C002', ('A001C002', None)), ('A001C002', ('A001C002', ('A001C002', ('A001C002', None)))))

...这不太好。

这可以重写并且仍然使用递归吗?还是我应该考虑另一种方法?

【问题讨论】:

  • 请出示您的实际结果。您在上面写的return 声明永远不会产生您发布的结果。
  • 我想你的意思是在排序列表中找到一个字符串,因为所有列表都是有序的。
  • 干杯,我已经解决了两个 cmets。
  • 当我在此数据上运行您的代码时,drive_inv = ['A001C000', 'A001C000', 'A001C001', 'A001C002', 'A001C002', 'A001C002', 'A001C003', 'A001C003', 'A001C003', 'A001C004', 'A001C005'] 并调用了find_media('A001C002', drive_inv),它返回了(None, None),将全局found 设置为['A001C002', 'A001C002', 'A001C002'],将全局missing 设置为@ 987654332@。您说效果很好,您希望返回的元组值究竟是什么?
  • 我希望元组返回('A001C002', 'A001C002', 'A001C002'),而不是使用全局列表。最初,该算法是一个类方法,所以附加到 self.found 很好 - 但我宁愿它是一个全局函数并与其他类共享它。我觉得它不属于某个特定的类,所以我不想使用组合/继承。

标签: python search binary-search


【解决方案1】:

虽然可以修改您的代码以使其执行您想要的操作,但可以使用下面显示的方法完成相同的操作 - 这可能更快并且不需要对字符串列表进行排序。

from collections import Counter

def find_media(media, drive_inv):
    cnt = Counter(drive_inv).get(media, 0)
    return (media,)*cnt if cnt else None

drive_inv = ['A001C000', 'A001C000', 'A001C001', 'A001C002', 'A001C002',
             'A001C002', 'A001C003', 'A001C003', 'A001C003', 'A001C004',
             'A001C005']

print find_media('A001C002', drive_inv) # -> ('A001C002', 'A001C002', 'A001C002')
print find_media('A001C099', drive_inv) # -> None

如果您希望它在找不到media而不是None时返回一个空元组,请将函数的返回语句更改为:

    return (media,)*cnt

【讨论】:

  • @tedwood:我应该指出的一个区别是,与您的代码不同,这种方法区分大小写。如果这是一个问题,我至少可以想到几种方法来使使用的字符串不区分大小写。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 2015-09-11
  • 2021-08-15
  • 1970-01-01
相关资源
最近更新 更多