如何迭代命名元组列表,按键值过滤分组得到匹配的音频文件组合
问题描述
现有3个存储命名元组的列表,分别对应鼓轨、旋律轨、贝斯轨的音频信息,代码如下:
drumlist = [drums( title='99_drumtrack_1.wav', bpm='99'), drums( title='95_drumtrack_2.wav', bpm='95'), drums( title='93_drumtrack_3.wav', bpm='93'), #etc... ] melodylist = [melody( title='99_Abmin_melodytrack_1.wav', bpm='99', key='Abmin'), melody( title='95_Bbmin_melodytrack_2.wav', bpm='95' ,key='Bbmin'), melody(title='93_Fmaj_melodytrack_3.wav', bpm='93' , key='Fmaj'), melody(title='92_Gmaj_melodytrack_4.wav', bpm='92' , key='Gmaj') #etc... ] basslist = [bass( title='99_Abmin_basstrack_1.wav', bpm='99', key='Abmin'), bass(title='95_Bbmin_basstrack_2.wav', bpm='95', key='Bbmin'), bass(title='93_Fmaj_basstrack_3.wav', bpm='93', key='Fmaj') #etc... ]
需要实现的匹配规则:按bpm匹配,同时旋律、贝斯的key(调性)一致的三个文件分为一组,每组生成sound1(鼓文件名)、sound2(旋律文件名)、sound3(贝斯文件名)三个变量供后续处理,期望输出示例如下:
#interation 1 sound1 = 99_drumtrack_1.wav sound2 = 99_Abmin_melodytrack_1.wav #KEYNOTE Abmin key for melody matches Abmin key for bass sound3 = 99_Abmin_basstrack_1.wav #KEYNOTE Abmin key for bass matches Abmin key for melody #use sound1, sound2 & sound3 variables further #interation 2 sound1 = 95_drumtrack_2.wav sound2 = 95_Bbmin_melodytrack_2.wav sound3 = 95_Bbmin_basstrack_2.wav #use sound1, sound2 & sound3 variables further #etc...
当前用嵌套for循环实现缩进层级过多,希望得到更简洁高效的实现方案。
解决方案
推荐用索引映射的方案,完全避免多层嵌套循环,逻辑清晰且效率更高:
# 1. 先构建两个索引字典,把查询复杂度降到O(1) # 鼓轨按bpm做索引,key为bpm值,value为对应鼓轨文件名 drum_index = {d.bpm: d.title for d in drumlist} # 贝斯轨按 (bpm, key) 复合条件做索引,key为(bpm, key)元组,value为贝斯文件名 bass_index = {(b.bpm, b.key): b.title for b in basslist} # 2. 直接遍历旋律轨匹配即可 for idx, melo in enumerate(melodylist, 1): # 同时匹配到对应bpm的鼓、对应bpm+key的贝斯才输出 if melo.bpm in drum_index and (melo.bpm, melo.key) in bass_index: sound1 = drum_index[melo.bpm] sound2 = melo.title sound3 = bass_index[(melo.bpm, melo.key)] # 此处直接调用三个变量做后续业务处理即可 print(f"# iteration {idx}") print(f"sound1 = {sound1}") print(f"sound2 = {sound2} #KEYNOTE {melo.key} key for melody matches {melo.key} key for bass") print(f"sound3 = {sound3} #KEYNOTE {melo.key} key for bass matches {melo.key} key for melody") print("# use sound1, sound2 & sound3 variables further\n")
如果存在同个bpm对应多个鼓轨的场景,只需把鼓索引的value改为列表存储即可,调整代码如下:
from collections import defaultdict drum_index = defaultdict(list) for d in drumlist: drum_index[d.bpm].append(d.title) # 匹配时遍历对应bpm下的所有鼓轨即可 for idx, melo in enumerate(melodylist, 1): if melo.bpm in drum_index and (melo.bpm, melo.key) in bass_index: for drum_title in drum_index[melo.bpm]: sound1 = drum_title sound2 = melo.title sound3 = bass_index[(melo.bpm, melo.key)] # 后续业务逻辑
内容的提问来源于stack exchange,提问作者Andrew Jackson
相关产品推荐
相关产品推荐

