微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

根据Python中的当前值和下一个值更改列表中元素的顺序

如何解决根据Python中的当前值和下一个值更改列表中元素的顺序

我试图根据该列表中的当前值和下一个值来更改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类型时,只需以随机顺序创建列表即可。

当然,只要它们能达到这个目的,我就可以接受完全不同的方法

解决方法

算法

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,('Tenet',2020,('Blade Runner',1982,('The Tree of Life',2011,'experimental'),('Pi',1998,'experimental')]
print(make_playlist(videofiles))
# [('Blade Runner',('Star Gate','experimental')]

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。