【问题标题】:Counting strings in lists and then filtering & matching, in python在python中计算列表中的字符串,然后过滤和匹配
【发布时间】:2020-02-19 19:48:14
【问题描述】:

我有一个单词列表,使用 python3 我计算每个单词组合之间的字母差异(使用clever diff_summing algorithm from this site):

import itertools

def diff_letters(a,b):
    return sum ( a[i] != b[i] for i in range(len(a)) )

w = ['AAHS','AALS','DAHS','XYZA']

for x,y in itertools.combinations(w,2):
    if diff_letters(x,y) == 1:
        print(x,y)

打印出来:

AAHS AALS
AAHS DAHS

我的问题:我如何计算字符串“DAHS”和“AALS”只有一个合作伙伴,而“AAHS”有两个合作伙伴?我将过滤每个target_string正好一个 near_matching_word 的方向组合,所以我的最终数据(作为 JSON)看起来像这样:

[
 {
   "target_word": "DAHS",
   "near_matching_word": "AAHS"
 },
 {
   "target_word": "AALS",
   "near_matching_word": "AAHS"
 }
]

(注意 AAHS 没有显示为 target_word

我有一个使用functools.reduce的版本

import itertools
import functools
import operator

def diff_letters(a,b):
    return sum ( a[i] != b[i] for i in range(len(a)) )

w = ['AAHS','AALS','DAHS','XYZA']

pairs = []
for x,y in itertools.combinations(w,2):
    if diff_letters(x,y) == 1:
        #print(x,y)
        pairs.append((x,y))

full_list = functools.reduce(operator.add, pairs)
for x in full_list:
    if full_list.count(x) == 1:
        print (x)

打印出来的

AALS
DAHS

但是我必须回到我的大名单pairs 才能找到near_matching_word。当然,在我的最终版本中,pairs 列表会更大,target_word 可以是元组 (x,y) 中的第一项或第二项。

【问题讨论】:

    标签: python arrays python-3.x algorithm string-matching


    【解决方案1】:

    即使找到多个对,其他答案也会保留所有对。由于不需要它们,这似乎浪费了内存。这个答案只为每个字符串保留最多一对。

    import collections
    import itertools
    
    def diff_letters(a,b):
        return sum ( a[i] != b[i] for i in range(len(a)) )
    
    w = ['AAHS','AALS','DAHS','XYZA']
    
    # Marker for pairs that have not been found yet.
    NOT_FOUND = object()
    
    # Collection of found pairs x => y. Each item is in one of three states:
    # - y is NOT_FOUND if x has not been seen yet
    # - y is a string if it is the only accepted pair for x
    # - y is None if there is more than one accepted pair for x
    pairs = collections.defaultdict(lambda: NOT_FOUND)
    
    for x,y in itertools.combinations(w,2):
        if diff_letters(x,y) == 1:
            if pairs[x] is NOT_FOUND:
                pairs[x] = y
            else:
                pairs[x] = None
            if pairs[y] is NOT_FOUND:
                pairs[y] = x
            else:
                pairs[y] = None
    
    # Remove None's and change into normal dict.
    pairs = {x: y for x, y in pairs.items() if y}
    
    for x, y in pairs.items():
        print("Target = {}, Only near matching word = {}".format(x, y))
    

    输出:

    Target = AALS, Only near matching word = AAHS
    Target = DAHS, Only near matching word = AAHS
    

    【讨论】:

      【解决方案2】:

      您可以使用字典而不是对列表:

      pairs = {}
      for x, y in itertools.combinations(w, 2):
          if diff_letters(x, y) == 1:
              pairs.setdefault(x, []).append(y)
              pairs.setdefault(y, []).append(x)
      
      result = [{ "target_word": key, "near_matching_word": head, } for key, (head, *tail) in pairs.items() if not tail]
      
      print(result)
      

      输出

      [{'target_word': 'AALS', 'near_matching_word': 'AAHS'}, {'target_word': 'DAHS', 'near_matching_word': 'AAHS'}]
      

      pairs 字典中,键是target_words,值是near_matching_words。然后使用列表推导过滤掉超过 1 个near_matching_word 的那些。

      【讨论】:

      • 巧妙地使用 pairs 和 x 和 y 作为键,每个附加 y 和 x。
      【解决方案3】:
      import itertools
      import functools
      import operator
      
      
      def diff_letters(a, b):
          return sum(a[i] != b[i] for i in range(len(a)))
      
      
      w = ['AAHS', 'AALS', 'DAHS', 'XYZA']
      
      pairs = []
      for x, y in itertools.combinations(w, 2):
          if diff_letters(x, y) == 1:
              pairs.append((x, y))
      
      full_list = functools.reduce(operator.add, pairs)
      
      result = []
      
      for x in set(full_list):
          if full_list.count(x) == 1:
              pair = next((i for i in pairs if x in i))
              match = [i for i in pair if i != x][0]
              result.append({
                  "target_word": x,
                  "near_matching_word": match
              })
      
      print(result)
      

      输出:

      [{'target_word': 'DAHS', 'near_matching_word': 'AAHS'}, {'target_word': 'AALS', 'near_matching_word': 'AAHS'}]
      

      【讨论】:

      • 这可能不是最简洁的方法,但它确实有效。愿意解释反对意见吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-02
      • 1970-01-01
      相关资源
      最近更新 更多