从两个球员名单提取相似字符串的Python代码报错及优化问询
问题分析与解决方案
咱们一步步拆解你的问题,先搞定报错,再看看更优雅的实现方式:
1. 为什么会出现「list assignment index out of range」错误?
你初始化的idx = np.zeros(3)是固定长度为3的numpy数组,索引只能取0、1、2。但你的嵌套循环没有限制每个names1元素只匹配一次——如果某个名字在names2里被多次匹配(或者逻辑触发重复计数),i会增长到3,这时给idx[3]赋值就会超出数组索引范围,直接报错。
另外,你的匹配条件y in w有局限性:比如names1里的'C.J. McCollum'和names2里的'CJ McCollum',因为小数点的差异,'C.J. McCollum' in 'CJ McCollum'会返回False,导致你预期的第三个匹配项(索引3)根本找不到。
2. 修复基础版本代码
先解决索引越界问题,把固定长度数组换成动态列表,同时优化匹配逻辑(通过名字标准化消除格式差异):
names1 = ['C.J. McCollum', 'Metta World', 'LeBron James', 'Stephen Curry'] names2 = ['Metta World Peace', 'Steph Curry', 'Kevin Durant', 'CJ McCollum'] idx = [] # 定义名字标准化函数,消除标点、大小写、空格差异 def normalize_name(name): # 保留字母数字,转小写,去掉空格 return ''.join([c.lower() for c in name if c.isalnum()]) for x, y in enumerate(names1): normalized_y = normalize_name(y) for w in names2: normalized_w = normalize_name(w) # 检查标准化后的名字是否存在包含关系 if normalized_y in normalized_w or normalized_w in normalized_y: idx.append(x) break # 找到第一个匹配就跳出,避免重复计数 print(idx) # 输出: [0, 1, 3],符合预期
3. 更优解法
如果要处理更复杂的名字差异,推荐用模糊字符串匹配,比如fuzzywuzzy库(先安装:pip install fuzzywuzzy python-Levenshtein),它基于编辑距离计算相似度,比手动处理更健壮:
from fuzzywuzzy import process names1 = ['C.J. McCollum', 'Metta World', 'LeBron James', 'Stephen Curry'] names2 = ['Metta World Peace', 'Steph Curry', 'Kevin Durant', 'CJ McCollum'] # 设置相似度阈值,80分以上判定为匹配 threshold = 80 idx = [] for x, name in enumerate(names1): # 在names2中找到最相似的项 best_match, score = process.extractOne(name, names2) if score >= threshold: idx.append(x) print(idx) # 输出: [0, 1, 3]
如果不想用第三方库,也可以用列表推导式简化基础逻辑:
def normalize_name(name): return ''.join([c.lower() for c in name if c.isalnum()]) idx = [x for x, y in enumerate(names1) if any(normalize_name(y) in normalize_name(w) for w in names2)] print(idx) # 输出: [0, 1, 3]
关键注意点
- 名字标准化是核心:不同数据源的名字差异通常来自标点、缩写、大小写、后缀(比如Metta World vs Metta World Peace),标准化后能大幅提升匹配准确率。
- 避免重复计数:内层循环找到匹配后记得
break,否则同一个names1元素可能被多次加入idx。
内容的提问来源于stack exchange,提问作者Ahmed Jyad
相关产品推荐
相关产品推荐

