嵌套for循环如何添加else语句使返回列表长度与原DataFrame一致
问题说明
定义了一个基于pos_tag从句子中提取符合指定词性组合的三元组词语的函数,原始代码如下:
def get_trigram(pos_1, pos_2, pos_3): all_trigram = [] for j in range(len(df)): trigram = [] if len(df['pos'][j]) >= 2: for i in range(len(df['pos'][j])): if df['pos'][j][i-2][1] == pos_1 and df['pos'][j][i-1][1] == pos_2 and df['pos'][j][i][1] == pos_3: trigram.append(df['pos'][j][i-2][0] + " " + df['pos'][j][i-1][0] + " " + df['pos'][j][i][0]) all_trigram.append(trigram) return all_trigram
函数可正常运行,但返回的all_trigram列表长度小于所处理的原始DataFrame长度。
问题根源是代码中的判断逻辑:
if len(df['pos'][j]) >= 2:
all_trigram.append(trigram)被写在了该if判断块内部,只有满足长度条件的行才会被追加结果,pos序列长度小于2的行没有任何内容被写入返回列表,最终导致返回长度和原DataFrame不匹配。
使用的DataFrame示例如下:
修正方案
不需要写复杂的分支逻辑,只需要把all_trigram.append(trigram)语句从if判断块中移出,放到每行循环的末尾即可——因为每次循环开头已经初始化了空的trigram列表,不满足if判断条件时,trigram本身就是空列表,直接追加就能满足长度对齐的要求。
另外原始代码的判断条件存在逻辑bug:提取三元组需要至少3个连续的词性标签,长度小于3时访问i-2位置的元素会触发索引越界,需要把判断阈值从2改为3。
修正后的完整代码:
def get_trigram(pos_1, pos_2, pos_3): all_trigram = [] for j in range(len(df)): trigram = [] # 三元组需要至少3个pos标签,避免索引越界 if len(df['pos'][j]) >= 3: for i in range(len(df['pos'][j])): if df['pos'][j][i-2][1] == pos_1 and df['pos'][j][i-1][1] == pos_2 and df['pos'][j][i][1] == pos_3: trigram.append(f"{df['pos'][j][i-2][0]} {df['pos'][j][i-1][0]} {df['pos'][j][i][0]}") # 无论是否匹配到三元组,都追加当前行的结果,保证长度和原DataFrame一致 all_trigram.append(trigram) return all_trigram
如果一定要显式写else语句实现,就在if判断块的同级位置添加else分支,追加空列表即可,写法如下:
def get_trigram(pos_1, pos_2, pos_3): all_trigram = [] for j in range(len(df)): trigram = [] if len(df['pos'][j]) >= 3: for i in range(len(df['pos'][j])): if df['pos'][j][i-2][1] == pos_1 and df['pos'][j][i-1][1] == pos_2 and df['pos'][j][i][1] == pos_3: trigram.append(f"{df['pos'][j][i-2][0]} {df['pos'][j][i-1][0]} {df['pos'][j][i][0]}") all_trigram.append(trigram) else: # pos长度不足3的行直接追加空列表 all_trigram.append([]) return all_trigram
两种写法效果完全一致,第一种把append移到循环末尾的写法更简洁,避免重复写追加逻辑。
内容的提问来源于stack exchange,提问作者odebear
相关产品推荐
相关产品推荐

