英文:
Is it possible to turn my complicated for loop into nested list comprehension?
问题
I'm working on a CSV that lists a bunch of songs, and now need to merge duplicate songs.
masterList
是一个列表的元组。每个列表代表一首歌曲。songsMatch()
输入两首歌曲,根据它们是否匹配输出False
或True
。
I was able to use list comprehension to create a list of pairs of matching songs, as follows:
matches = [
[masterList[index1], masterList(index2)]
for index1 in range(1, len(masterList)-2)
for index2 in range(index1+1, len(masterList))
if songsMatch(masterList[index1], masterList[index2])
]
However, I want all matching songs to be in the same sub-list, as opposed to creating three sub-lists. Here's some code I made that does more or less what I want:
matches = []
for index1 in range(1, len(masterList) - 2):
newList = [masterList[index1]]
for index2 in range(index1+1, len(masterList)):
if songsMatch(masterList[index1], masterList[index2]):
newList.append(masterList[index2])
if len(newList) != 1:
matches.append(newList)
This code more or less works. (If a song shows up 3 times, this still outputs a three-item list and then a two-item list, which isn't great but I think I can work with that.) However, I wanted to see if I could use nested list comprehension to rewrite this. Any ideas?
I tried something like this:
matches=[[masterList[index2] for index2 in range(index1+1, len(masterList)) if songsMatch(masterList[index1], masterList[index2])] for index1 in range(1, len(masterList)-2)]
When I printed out matches
, I noticed that there were lots of empty lists in my output, and I'm not sure why. Those are easy to deal with. However, the main thing I want is to make sure that if my inputs have If I were to use this code, I also would want to make sure that each sublist starts out with masterList[index1]
, meaning that both matching songs would be in the output as opposed to just the second one.
英文:
I'm working on a CSV that lists a bunch of songs, and now need to merge duplicate songs.
masterList
is a tuple of lists. Each list is a song.songsMatch()
inputs two songs and outputsFalse
orTrue
depending on whether or not the 2 songs match.
I was able to use list comprehension to create a list of pairs of matching songs, as follows:
matches = [
[masterList[index1], masterList(index2)]
for index1 in range(1, len(masterList)-2)
for index2 in range(index1+1, len(masterList))
if songsMatch(masterList[index1], masterList[index2])
]
However, I want all matching songs to be in the same sub-list, as opposed to creating three sub-lists. Here's some code I made that does more or less what I want:
matches = []
for index1 in range(1, len(masterList) - 2):
newList = [masterList[index1]]
for index2 in range(index1+1, len(masterList)):
if songsMatch(masterList[index1], masterList[index2]):
newList.append(masterList[index2])
if len(newList) != 1:
matches.append(newList)
This code more or less works. (If a song shows up 3 times, this still outputs a three-item list and then a two-item list, which isn't great but I think I can work with that.) However, I wanted to see if I could use nested list comprehension to rewrite this. Any ideas?
I tried something like this:
matches=[[masterList[index2] for index2 in range(index1+1, len(masterList)) if songsMatch(masterList[index1], masterList[index2])] for index1 in range(1, len(masterList)-2)]
When I printed out matches
, I noticed that there were lots of empty lists in my output, and I'm not sure why. Those are easy to deal with. However, the main thing I want is to make sure that if my inputs have If I were to use this code, I also would want to make sure that each sublist starts out with masterList[index1]
, meaning that both matching songs would be in the output as opposed to just the second one.
答案1
得分: 2
根据您的代码,这将是列表推导式。
matches = [
(masterList[index1], masterList[index2])
for index1 in range(1, len(masterList)-2)
for index2 in range(index1+1, len(masterList))
if songsMatch(masterList[index1], masterList[index2])
]
对于列表推导式中的嵌套循环,循环顺序是从左到右的,最左边的循环是最外层的,最右边的是最内层的。
英文:
Based on your code, this would be the list comprehension.
matches = [
(masterList[index1], masterList[index2])
for index1 in range(1, len(masterList)-2)
for index2 in range(index1+1, len(masterList))
if songsMatch(masterList[index1], masterList[index2])
]
For nested loops in list comprehensions, your loops go from left to right, such that the leftmost loop is the outermost one and rightmost is the innermost one.
答案2
得分: 0
如Lie Ryan在上面指出的那样,上面的代码只是:
matches = [(song1, song2)
for song1, song2 in itertools.combination(masterList, 2)
if songsMatch(song1, song2)
英文:
As pointed out by Lie Ryan above, the above code is just:
matches = [(song1, song2)
for song1, song2 in itertools.combination(masterList, 2)
if songsMatch(song1, song2)
答案3
得分: 0
以下是翻译好的部分:
一种方法是识别每个重复组的第一首歌曲(即那些没有先前匹配的歌曲),然后从这些歌曲中构建包含后续重复歌曲的组。从下一次迭代中删除重复项,以确保子组不会创建不必要的匹配。
注意:在推导中,我使用了一个临时列表 sl
,但如果您不需要重复项保留在主列表中,可以直接在主列表上进行操作
matches = [ [song]+[sl.pop(j) for j in dups[::-1]]
for sl in [masterList.copy()]
for i,song in enumerate(sl,1)
for dups in [[j for j,s in enumerate(sl[i:],i)
if songsMatch(s,song)]]
if dups]
不过,我不确定为什么您需要使用推导来实现这个。更高效的算法是通过仅比较当前组的已匹配歌曲中的一个来构建匹配组的列表(即利用传递性):
matches = []
for song in masterList:
for group in matches:
if songsMatch(group[0], song): # 仅匹配组的第一首歌曲就足够建立关联
group.append(song)
break
else:
matches.append([song]) # 无匹配开始新的组
matches = [group for group in matches if len(group) > 1]
<details>
<summary>英文:</summary>
One approach would be to identify the first song of each duplicate group (i.e. those with no previous match) and build groups from these songs with the subsequent ones that are duplicates. Removing the duplicates from the next iteration ensures that sub-groups will not create unwanted matches.
*Note: I'm using a temporary list `sl` in the comprehension but, if you don't need the duplicates to remain in the masterList, you can work directly on it*
matches = [ [song]+[sl.pop(j) for j in dups[::-1]]
for sl in [masterList.copy()]
for i,song in enumerate(sl,1)
for dups in [[j for j,s in enumerate(sl[i:],i)
if songsMatch(s,song)]]
if dups]
I'm not sure why you need this to be in a comprehension though. A more efficient algorithm would be to build the list of matching groups by comparing only one of the already matched song for each of the current groups (i.e. leveraging [transitivity][1]):
matches = []
for song in masterList:
for group in matches:
if songsMatch(group[0],song): # only matching 1st of group
group.append(song) # is enough to establish membership
break
else:
matches.append([song]) # no-match starts new group
matches = [group for group in matches if len(group)>1]
[1]: https://en.wikipedia.org/wiki/Transitive_relation
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论