检查列表中是否有字符串,具体取决于最后两个字符

时间:2017-05-15 09:17:48

标签: python loops dictionary range

设置向上

我正在使用Scrapy来收集住房广告。每个广告我检索一个邮政编码,该邮政编码由四个数字后跟2个字母组成,例如1053ZM

我有一张excel表格,通过以下方式将地区与邮政编码联系起来,

district    postcode_min    postcode_max
   A           1011AB           1011BD
   A           1011BG           1011CE
   A           1011CH           1011CZ

因此,第二行指出1011AB, 1011AC,..., 1011AZ, 1011BA,...,1011BD范围内的邮政编码属于区A

实际列表包含1214行。

<小时/> 的问题

我希望使用其邮政编码和列表将每个广告与其各自的区域相匹配。

我不确定最好的方法是什么,以及如何做到这一点。

我提出了两种不同的方法:

  1. postcode_minpostcode_max之间创建所有邮政编码,将所有邮政编码及其各自的区域分配到字典中,然后使用循环进行匹配。
  2. 即。创建,

     d = {'A': ['1011AB','1011AC',...,'1011BD',
                '1011BG','1011BH',...,'1011CE',
                '1011CH','1011CI',...,'1011CZ'],
          'B': [...],           
          }
    

    然后,

    found = False
    for distr in d.keys(): # loop over districts
         for code in d[distr]: # loop over district's postal codes
             if postal_code in code: # assign if ad's postal code in code                 
                 district = distr
                 found = True
                 break
             else:
                 district = 'unknown'
         if found:
             break
    
    1. 让Python理解postcode_minpostcode_max之间有一个范围,将范围及其各自的区域分配给字典,并使用循环进行匹配。
    2. 即。像,

      d = {'A': [range(1011AB,1011BD), range(1011BG,1011CE),range(1011CH,1011CZ)],
           'B': [...]
          }
      

      然后,

      found = False
      for distr in d.keys(): # loop over districts
           for range in d[distr]: # loop over district's ranges
               if postal_code in range: # assign if ad's postal code in range                 
                   district = distr
                   found = True
                   break
               else:
                   district = 'unknown'
           if found:
               break
      

      问题

      方法1:

      • 如何创建所有邮政编码并将其分配到字典?

      方法2:

      我使用range()作为解释性用途,但我知道range()不能像这样工作。

      • 如上例所示,我需要什么才能有效地拥有range()
      • 如何正确循环这些范围?

      我认为我的偏好取决于方法2,但我很乐意与其中任何一方合作。或者如果你有一个解决方案,可以使用其他解决方案。

2 个答案:

答案 0 :(得分:1)

您可以使用intervaltree来获得更好的查找速度,并将邮政编码解释为基数为36(10位和26个字母)的数字。

from intervaltree import IntervalTree
t = IntervalTree()
for district,postcode_min,postcode_max in your_district_table:
    # We read the postcode as a number in base 36
    postcode_min = int(postcode_min, 36)
    postcode_max = int(postcode_max, 36)
    t[postcode_min:postcode_max] = district

如果邮政编码包含在内(包括“最大”邮政编码),请改用:

    t[postcode_min:postcode_max+1] = district

最后,您可以按post_code这样查找地区:

def get_district(post_code):
    intervals = t[int(post_code, 36)]
    if not intervals:
        return None
    # I assume you have only one district that matches a postal code
    return intervals[0][2] # The value of the first interval on the list

答案 1 :(得分:1)

你可以像这样收集excel中的值

d = {'A': ['1011AB', '1011BD', '1011BG', '1011CE',  '1011CH', '1011CZ'],
     'B': ['1061WB', '1061WB'],
     }

def is_in_postcode_range(current_postcode, min, max):
    return min <= current_postcode <= max

def get_district_by_post_code(postcode):
    for district, codes in d.items():
        first_code = codes[0]
        last_code = codes[-1]
        if is_in_postcode_range(postcode, first_code, last_code):
            if any(is_in_postcode_range(postcode, codes[i], codes[i+1]) for i in range(0, len(codes), 2)):
                return district
            else:
                return None

用法:

print get_district_by_post_code('1011AC'): A
print get_district_by_post_code('1011BE'): None
print get_district_by_post_code('1061WB'): B