【问题标题】:Changing the order of elements in a list based on current and next value in Python根据Python中的当前值和下一个值更改列表中元素的顺序
【发布时间】:2021-02-15 00:43:53
【问题描述】:

我正在尝试根据列表中的当前值和下一个值更改 Python 列表中元素的顺序。我想使用此排序来创建一个视频播放列表,其中不包含特定类型的两个连续视频。该列表将被转换为 m3u 播放列表。

我的情况: 我已按以下方式命名我拥有的所有视频:“电影标题”-“发行年份”-“类型”。

例如,我不希望播放列表包含两部连续的动作片。唯一的例外应该是当我使用仅包含动作电影的动作电影目录时。然后可以按随机顺序构建播放列表。

我目前有以下代码:

import os
import glob
from threading import Timer

cwd = os.getcwd()

# create list
videofiles = []

for file in glob.glob('**/*.mp4', recursive=True):
    videofiles.append(file)

# split file on last index to compare genre
def sortSplit(file):
    return file.split('- ',2)[2] 


randomvideo = []
   
for file in videofiles:
          randomvideo.append(sortSplit(file))

randomvideo.sort()

当我使用 sortSplit 函数时,我得到了我想要比较的索引/字符串。但是,我有以下问题:

  • 拆分是否会“记住”原始字符串,以便在构建列表时包含完整的文件名?
  • 我找不到比较列表中当前元素和下一个元素的方法

对于最后一部分,示例列表可以是:

['movie-year-ACTION', 'movie-year-ACTION', 'movie-year-SCIFI', 'movie-year-DOCUMENTARY']

列表排序应该查看第一个元素中的 ACTION,将其与下一个元素进行比较,看看它们是否相同,然后将下一个元素切换为不是 ACTION 但可以是其他任何类型的类型。由于我预计类型的数量会增长,因此我正在寻找一种方法,例如,这些类型不会固定在另一个列表中。同样,唯一的例外是当列表中的所有元素都是 ACTION 类型时,只需按随机顺序创建列表。

当然,只要能达到这个目的,我对完全不同的方法持开放态度。

【问题讨论】:

  • 如果我理解正确,您想按年份和流派对文件列表进行排序(ACTION 应该是第一个,然后是 SCI-FI 等...)?
  • 流派的顺序并不重要,我实际上更喜欢每次都创建一个新列表,唯一的规则是两个连续的流派不能以这种方式排序,除了当所有文件属于同一类型时,只需创建这些文件的随机顺序
  • 是否有任何边缘情况,例如,如果您列出有 3 部动作片和 1 部恐怖片会怎样。在这种情况下,您最终会得到 2 个彼此相邻的相同内容。
  • 我想到了这些场景,但我还没有想出解决方案。正如我预计总交易量会随着时间而变化,理论上这样的情况可能会发生。如果是这种情况,我当然会接受这种情况。

标签: python list sorting playlist


【解决方案1】:

算法

forbidden_genre = None
While there are movies in the database:
  Pick a movie from the non-forbidden genre which has largest remaining number of movies
  Remove that movie from database, add it to playlist
  forbidden_genre = genre of that movie

请注意,我们总是从剩余电影数量最多的类型中选择一个动作,以避免陷入其中一种类型仍然有很多电影而其他类型的电影不够多的位置交替使用。

Python 代码

为了能够按类型选择电影,我们将首先使用 itertools.groupby 按类型对电影进行分组。在下面的代码中,我们可以使用sortedbysize_groups[genre_index][0] 访问一个类型的名称,并使用sortedbysize_groups[genre_index][1] 访问该类型的剩余电影列表

import operator   # itemgetter(2)
import itertools  # groupby

def make_playlist(videofiles):
  groups_tmp = itertools.groupby(sorted(videofiles, key=operator.itemgetter(2)), operator.itemgetter(2))
  sortedbysize_groups = sorted([(k, list(g)) for k,g in groups_tmp], key=lambda p: len(p[1]))
  playlist = []
  forbidden_genre = None
  while len(sortedbysize_groups) > 1:
    genre_index = get_next_nonforbidden_index(sortedbysize_groups, forbidden_genre)
    next_film = sortedbysize_groups[genre_index][1].pop()
    forbidden_genre = sortedbysize_groups[genre_index][0]
    playlist.append(next_film)
    if len(sortedbysize_groups[genre_index][1]) == 0:
      sortedbysize_groups.pop(genre_index)
    else:
      move_back_if_necessary_to_keep_sorted(sortedbysize_groups, genre_index % len(sortedbysize_groups))
  playlist.extend(sortedbysize_groups[0][1])
  return playlist

def get_next_nonforbidden_index(sortedbysize_groups, forbidden_genre):
  return (-1) if (sortedbysize_groups[-1][0] != forbidden_genre) else (-2)

def move_back_if_necessary_to_keep_sorted(sortedbysize_groups, i):
  while i > 0 and len(sortedbysize_groups[i-1][1]) > len(sortedbysize_groups[-1][1]):
    i -= 1
  if i < len(sortedbysize_groups) - 1:
    sortedbysize_groups[i], sortedbysize_groups[-1] = sortedbysize_groups[-1], sortedbysize_groups[i]

videofiles = [('Star Gate', 1994, 'scifi'), ('Good Will Hunting', 1997, 'drama'), ('A Beautiful Mind', 2001, 'drama'), ('Tenet', 2020, 'scifi'), ('Blade Runner', 1982, 'scifi'), ('The Tree of Life', 2011, 'experimental'), ('Pi', 1998, 'experimental')]
print(make_playlist(videofiles))
# [('Blade Runner', 1982, 'scifi'), ('Pi', 1998, 'experimental'), ('A Beautiful Mind', 2001, 'drama'), ('Tenet', 2020, 'scifi'), ('Good Will Hunting', 1997, 'drama'), ('Star Gate', 1994, 'scifi'), ('The Tree of Life', 2011, 'experimental')]

如果由于一种类型的电影太多而没有完美的解决方案,算法会尽力而为,播放列表将以该类型的两部电影或更多电影结尾。请注意,只有在严格意义上超过一半的电影属于同一类型时才会发生这种情况。

【讨论】:

  • 首先,非常感谢您付出的努力。我正在阅读它并试图从中学习。但是我有一个问题:当我运行代码时,在“move_back_if_necessary_to_keep_sorted(sortedbysize_groups, i % len(sortedbysize_groups))”行出现错误。它说“我”没有定义。我在这里错过了什么?
  • @borisvdh 看起来我帖子中的代码版本与我的计算机上的版本不同 - 现在应该修复它。变量 i 已重命名为 genre_index 以提高可读性。
  • 我建议打印变量 sortedbysize_groups 以了解发生了什么,特别是如果您不熟悉 itertools.groupby
  • 非常感谢您的回答和代码。我尝试了它并且它有效,所以现在我可以仔细研究它并从中学习。我对答案进行了投票,但新用户对公开显示的分数没有影响
猜你喜欢
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 2021-12-11
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
相关资源
最近更新 更多