【问题标题】:Python large array comparisonPython大数组比较
【发布时间】:2017-03-01 00:58:32
【问题描述】:

我有一个包含 URL 的大数组(它可以包含 100 000 个 URL 字符串),我想知道我的实际 URL 是否是数组中的一个 URL。为此,我必须将实际的 URL 字符串与数组中的所有 URL 字符串进行比较。有什么方法可以与这个大数组进行比较,但时间比我现在少吗?现在是:

error = 0
for oldUrl in urlList:
    error = 1 if oldUrl == actualUrl else error

【问题讨论】:

    标签: python arrays performance python-2.7 compare


    【解决方案1】:

    正如@Laurent 和@sisanared 已经提到的,您可以使用in 运算符作为listssets 来检查成员资格。例如:

    found = x in some_list
    if found: 
        #do stuff
    else:
        #other stuff
    

    但是,您提到速度是一个问题。 TL;DR -- 如果set 已经存在,sets 会更快。从https://wiki.python.org/moin/TimeComplexity 开始,使用in 运算符检查成员资格对于list 是O(n),对于set 是O(1)(就像@enderland 指出的那样)。

    对于 100,000 项或一次性检查,它可能对您使用的影响不大,但对于大量项目或您将进行多次检查的情况,您可能应该使用set。我从解释器做了几个测试,这就是我发现的(Python 2.7,i3 Windows 10 64bit):

    import timeit
    #Case 1: Timing includes building the list/set
    def build_and_check_a_list(n):
        a_list = [ '/'.join( ('http:stackoverflow.com',str(i)) ) for i in xrange(1,n+1) ]
        check = '/'.join( ('http:stackoverflow.com',str(n)) )
        found = check in a_list
        return (a_list, found)
    
    def build_and_check_a_set(n):
        a_set = set( [ '/'.join( ('http:stackoverflow.com',str(i)) ) for i in xrange(1,n+1) ] )
        check = '/'.join( ('http:stackoverflow.com',str(n)) )
        found = check in a_set
        return (a_set, found)
    
    timeit.timeit('a_list, found = build_and_check_a_list(100000)', 'from __main__ import build_and_check_a_list', number=50)
    3.211972302022332
    
    timeit.timeit('a_set, found = build_and_check_a_set(100000)', 'from __main__ import build_and_check_a_set', number=50)
    4.5497120006930345
    
    #Case 2: The list/set already exists (timing excludes list/set creation)
    check = '/'.join( ('http:stackoverflow.com',str(100000)) )
    
    timeit.timeit('found = check in a_list', 'from __main__ import a_list, check', number=50)
    0.12173540635194513
    
    timeit.timeit('found = check in a_set', 'from __main__ import a_set, check', number=50)
    1.01052391983103e-05
    

    对于 100 万个条目,在我的计算机上建立和/或检查成员资格:

    #Case 1: list/set creation included
    timeit.timeit('a_list, found = build_and_check_a_list(1000000)', 'from __main__ import build_and_check_a_list', number=50)
    35.71641090788398
    
    timeit.timeit('a_set, found = build_and_check_a_set(1000000)', 'from __main__ import build_and_check_a_set', number=50)
    51.41244436103625
    
    #Case 2: list/set already exists
    check = '/'.join( ('http:stackoverflow.com',str(1000000)) )
    
    timeit.timeit('found = check in a_list', 'from __main__ import a_list, check', number=50)
    1.3113457772124093
    
    timeit.timeit('found = check in a_set', 'from __main__ import a_set, check', number=50)
    8.180430086213164e-06
    

    【讨论】:

      【解决方案2】:

      不要为此使用列表。在列表中查找的最坏情况复杂度为 O(n)。

      改为使用集合(或字典,如果您有其他元数据)。这具有大约 O(1) 的查找。有关集合、字典和列表之间的比较,请参阅 here

      使用集合,查找很简单:

      urls = set(['url1', 'url2', 'url3'])
      
      print ('url2' in urls)
      print ('foobar' in urls)
      

      或者在您的情况下,将您的列表对象转换为一个集合:

      urlListSet = set(urlList)
      print(oldUrl in urlListSet)
      

      您还可以将新的网址添加到您的集合中:

      urlListSet.add(newurl)
      urlListSet.update(listOfNewUrls)
      

      【讨论】:

        【解决方案3】:

        要检查list 是否包含item,请使用:item in list

        所以,你可以写:

        error = oldUrl in urlList
        

        【讨论】:

          猜你喜欢
          • 2018-09-18
          • 1970-01-01
          • 2022-01-11
          • 2012-04-16
          • 1970-01-01
          • 2022-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多