找到应该相等的不同字符串之间的相等性

时间:2014-03-19 15:31:54

标签: python design-patterns equality

我有三个不同来源的足球队数据。但是,'团队名称'对于来自这些来源的同一团队,风格各不相同。 例如,

[Source1]             [Source2]  [Source3]
Arsenal               ARS        Arsenal
Manchester United     MNU        ManUtd
West Bromwich Albion  WBA        WestBrom

现在我经常需要比较这些球队名称(来自不同或相同的来源),以检查他们是相同或不同的球队。例如,

Arsenal == ARS  : True
MNU == WBA      : False
WBA == WestBrom : True

我想知道是否有一种巧妙的pythonic方法来实现这一点。

我的想法如下: 创建一个类Team,其中包含一个包含元组的元组列表,其中包含3个匹配的团队名称。实例化。每个团队名称的Team对象。然后覆盖类的__eq__方法,我将在元组列表上执行reduce,以查找相关的两个团队名称是否属于表示相等的相同元组。< / p>

一些伪代码:

class Team:
  def __init__(self, teamname):
    self.teams = [(Arsenal, ARS, Arsenal),
                  (Manchester United, MNU, ManUtd),
                  (West Bromwich Albion, WBA, WestBrom),]
    self.teamname = teamname

  def __eq__(self, teamA, teamB):
    reduce(self.teams, <check if teamA and teamB in same tuple>)

思想?

P.S。:请为这个问题建议一个更好的标题,因为我不认为我做得很好。

编辑:扩展了我建议的解决方案

5 个答案:

答案 0 :(得分:6)

为简单起见,您可以将所有内容放在平面规范查找中:

canonical = {'Arsenal':'ARS',
             'ARS':'ARS',
             'Manchester United':'MNU',
             'MNU':'MNU',
             'ManUtd':'MNU',
             ...}

然后等价测试很容易:

if canonical[x] == canonical[y]:
    #they're the same team

这里有很多很好的替代答案,如此广泛的图片:如果你不希望你的canonical查找发生变化,这种方法很好。您可以生成一次然后忘记它。如果 频繁更改,那么维护就会很糟糕,所以你应该去别处看看。

答案 1 :(得分:1)

你可以有某种等价映射:

equivalents = {"Arsenal": ["ARS",], 
               "Manchester United": ["MNU", "ManUtd"], ...}

并使用它来处理您的数据:

>>> name = "ManUtd"
>>> for main, equivs in equivalents.items():
    if name == main or name in equivs:
        name = main
        break

>>> name 
"Manchester United"

这使您可以轻松查看您认为的&#34;规范名称&#34;对于团队(即密钥)和被认为是同一团队的其他名称(即列表值)。


如果你沿着课程路线走下去,你应该让团队元组列表成为一个类属性:

class Team:

    TEAMS = [("Arsenal", "ARS"), ("Manchester United", "MNU", "ManUtd"), ...]

    def __init__(self, name):
        if not any(name in names for names in self.TEAMS):
            raise ValueError("Not a valid team name.")
        self.name = name

    def __eq__(self, other):
        for names in self.TEAMS:
            if self.name in names and other.name in names:
                return True
        return False

此输出:

>>> mnu1 = Team("ManUtd")
>>> mnu2 = Team("MNU")
>>> mnu1 == mnu2
True

>>> ars = Team("ARS")
>>> ars == mnu1
False

>>> fail = Team("Not a name")
Traceback (most recent call last):
  File "<pyshell#49>", line 1, in <module>
    fail = Team("Not a name")
  File "<pyshell#43>", line 7, in __init__
    raise ValueError("Not a valid team name.")
ValueError: Not a valid team name.

或者,如果您的Team不具备其他属性,那么只需一个简单的函数即可完成同样的工作:

def equivalent(team1, team2):
    teams = [("Arsenal", "ARS"), ("Manchester United", "MNU", "ManUtd"), ...]
    for names in teams:
        if team1 in names and team2 in names:
            return True
    return False

此输出:

>>> equivalent("MNU", "ManUtd")
True
>>> equivalent("MNU", "Arsenal")
False
>>> equivalent("MNU", "Not a name")
False

答案 2 :(得分:1)

如果定义一个反转字典的函数,则可以更好地维护roippi的代码:

def invertdict(d):
  id=dict()
  for (key,value) in d.items():
    for part in value:
      if part in id:
        id[part]=id[part]+(key,)
      else:
          id[part]=(key,)
  return id

如果你这样做,canonical的值必须定义为元组:

canonical = {'Arsenal':('ARS',),
             'ARS':('ARS',),
             'Manchester United':('MNU',),
             'MNU':('MNU',),
             'ManUtd':('MNU',)}

然后你可以简单地说:

print invertdict(canonical)
{'ARS': ('ARS', 'Arsenal'), 'MNU': ('ManUtd', 'Manchester United', 'MNU')}
print invertdict(invertdict(canonical))
{'MNU': ('MNU',), 'Manchester United': ('MNU',), 'ARS': ('ARS',), 'Arsenal': ('ARS',), 'ManUtd': ('MNU',)}
# this is canonical again

然后你可能想要在开头定义倒置规范并使用invertdict来获得canonical并能够比较你的团队

希望有所帮助

答案 3 :(得分:0)

我会做什么:

class Team:
    def __init__(self, name, all_names):
        self.name = name  # use name as it's "proper" name
        self.all_names = all_names # use a list of all acceptable names and abbreviaitons

man = Team('Manchester United',['Manchester United', 'MNU', 'ManUtd'])

然后您可以使用if 'MNU' in man.all_names

答案 4 :(得分:0)

我认为使用所有相关名称的元组列表,最好的方法是接近你所拥有的。

def __eq__(self, teamA, teamB):
    for names in self.teams:
        if teamA in names:  break

    if (teamA and teamB) in names: #Must include teamA in this comparison to avoid false positive from last entry of self.teams containing teamB but not teamA
         return True
    else:
         return False

这比使用dict或缩写列表更有优势,因为使用哪个名称版本作为“键”并不重要


您可以尝试使用以下内容自动匹配:

def __eq__(self, teamA, teamB):
    if len(teamA) > len(teamB):
        return all([l in teamA.lower() for l in teamB.lower()])
    elif len(teamA) < len(teamB):
        return all([l in teamB.lower() for l in teamA.lower()])
    else:
        return teamA.lower() == teamB.lower()

请注意,此方法并不完美,因为它要求缩写的所有字母都在完整版本中(可能并非总是如此)。您可以构建一个比我在这里更复杂的匹配方案,这将获得更可靠的结果