我有三个不同来源的足球队数据。但是,'团队名称'对于来自这些来源的同一团队,风格各不相同。 例如,
[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。:请为这个问题建议一个更好的标题,因为我不认为我做得很好。
编辑:扩展了我建议的解决方案
答案 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()
请注意,此方法并不完美,因为它要求缩写的所有字母都在完整版本中(可能并非总是如此)。您可以构建一个比我在这里更复杂的匹配方案,这将获得更可靠的结果