python 如何保持列表中的顺序?

rta7y2nd  于 2023-01-04  发布在  Python
关注(0)|答案(2)|浏览(105)

我想返回一个字符串,该字符串表示所有照片的新名称列表,其顺序与原始字符串相同,但是final_string当前的顺序不同。

def fetch_date_time(photo):
    return photo.split(", ")[2]

def prefixed_number(n, max_n):
    len_n = len(str(n))
    len_max_n = len(str(max_n))
    prefix = "".join(["0" for i in range(len_max_n - len_n)]) + str(n)
    return prefix

def solution(S):
    list_of_pics = S.split("\n")
    city_dict = {}

    for pic in list_of_pics:
        city = pic.split(", ")[1]
        if city in city_dict:
            city_dict[city].append(pic)
        else:
            city_dict[city] = [pic]

    final_string = ""

    for city_group in city_dict:
        city_dict[city_group].sort(key=fetch_date_time)
        for ind, photo in enumerate(city_dict[city_group]):
            city = photo.split(",")[1]
            ext = photo.split(", ")[0].split(".")[-1]
            max_len = len(city_dict[city_group])
            number = prefixed_number(ind + 1, max_len)
            city_dict[city_group][ind] = city + number + "." + ext + "\n"
        final_string += "".join(city_dict[city_group])

    return final_string

string = """photo.jpg, Warsaw, 2013-09-05 14:08:15
john.png, London, 2015-06-20 15:13:22
myFriends.png, Warsaw, 2013-09-05 14:07:13
Eiffel.jpg, Paris, 2015-07-23 08:03:02
pisatower.jpg, Paris, 2015-07-22 23:59:59
BOB.jpg, London, 2015-08-05 00:02:03
notredame.png, Paris, 2015-09-01 12:00:00
me.jpg, Warsaw, 2013-09-06 15:40:22
a.png, Warsaw, 2016-02-13 13:33:50
b.jpg, Warsaw, 2016-01-02 15:12:22
c.jpg, Warsaw, 2016-01-02 14:34:30
d.jpg, Warsaw, 2016-01-02 15:15:01
e.png, Warsaw, 2016-01-02 09:49:09
f.png, Warsaw, 2016-01-02 10:55:32
g.jpg, Warsaw, 2016-02-29 22:13:11"""

print(solution(string))

我的当前输出:

Warsaw01.png
 Warsaw02.jpg
 Warsaw03.jpg
 Warsaw04.png
 Warsaw05.png
 Warsaw06.jpg
 Warsaw07.jpg
 Warsaw08.jpg
 Warsaw09.png
 Warsaw10.jpg
 London1.png
 London2.jpg
 Paris1.jpg
 Paris2.jpg
 Paris3.png

预期产出:

Warsaw02.jpg
London1.png
Warsaw01.png
Paris2.jpg
Paris1.jpg
London2.jpg
Paris3.png
Warsaw03.jpg
Warsaw09.png
Warsaw07.jpg
Warsaw06.jpg
Warsaw08.jpg
Warsaw04.png
Warsaw05.png
Warsaw10.jpg
kupeojn6

kupeojn61#

下面的代码可能会有所帮助。

string = """photo.jpg, Warsaw, 2013-09-05 14:08:15
john.png, London, 2015-06-20 15:13:22
myFriends.png, Warsaw, 2013-09-05 14:07:13
Eiffel.jpg, Paris, 2015-07-23 08:03:02
pisatower.jpg, Paris, 2015-07-22 23:59:59
BOB.jpg, London, 2015-08-05 00:02:03
notredame.png, Paris, 2015-09-01 12:00:00
me.jpg, Warsaw, 2013-09-06 15:40:22
a.png, Warsaw, 2016-02-13 13:33:50
b.jpg, Warsaw, 2016-01-02 15:12:22
c.jpg, Warsaw, 2016-01-02 14:34:30
d.jpg, Warsaw, 2016-01-02 15:15:01
e.png, Warsaw, 2016-01-02 09:49:09
f.png, Warsaw, 2016-01-02 10:55:32
g.jpg, Warsaw, 2016-02-29 22:13:11"""

class row:
  def __init__(self, image, city, date):
    self.image = image
    self.city = city
    self.date = date

def read_rows(text):
  rows = []
  for line in text.split('\n'):
    image, city, date = line.split(',')
    rows.append(row(image, city, date))
  return rows

def rename_city(rows):
  known_cities = {}
  for row in rows:
    if row.city in known_cities:
      known_cities[row.city] += 1
      row.city = "%s%02d"%(row.city, known_cities[row.city])
    else:
      known_cities[row.city] = 1
      row.city += "01"

def get_citynames(rows):
  cities = []
  for row in rows:
    cities.append(row.city)
  return cities

def solution(input):
  rows = read_rows(input)
  sorted_rows = sorted(rows, key=lambda x: x.date)
  rename_city(sorted_rows)
  return get_citynames(rows)

print("\n".join(solution(string)))

产出

Warsaw02
 London01
 Warsaw01
 Paris02
 Paris01
 London02
 Paris03
 Warsaw03
 Warsaw09
 Warsaw07
 Warsaw06
 Warsaw08
 Warsaw04
 Warsaw05
 Warsaw10
qkf9rpyu

qkf9rpyu2#

要解决此问题,您需要:
1.按 * 城市 * 对数据进行分组;
1.按 * 日期 * 对属于同一城市的条目进行排序;
1.生成新的文件名并恢复到原来的顺序。
首先,我们需要将string的每一行拆分为", "

lines = [s.split(", ") for s in string.splitlines()]

1.要按城市对lines进行分组,我们可以使用两种不同的方法:
1.1.创建一个字典,其中city将是唯一键,value将是包含此城市的所有行的列表:

grouped_photos = {}
for line in lines:
    city = line[1]
    if city in grouped_photos:
        grouped_photos[city].append(line)
    else:
        grouped_photos[city] = [line]

这里你可以注意到,如果继续使用这个方法,生成lines是没有意义的,因为它会导致一次无用的迭代,我们可以在string.splitlines()上迭代:

grouped_photos = {}
for line in string.splitlines():
    splitted = line.split(", ")
    city = splitted[1]
    if city in grouped_photos:
        grouped_photos[city].append(splitted)
    else:
        grouped_photos[city] = [splitted]

我们还可以使用defaultdict来缩短代码:

from collections import defaultdict

...

grouped_photos = defaultdict(list)
for line in string.splitlines():
    splitted = line.split(", ")
    grouped_photos[splitted[1]].append(splitted)

1.2.使用groupby()。与前面方法的主要区别在于groupby()需要排序的数据。

from itertools import groupby
from operator import itemgetter

...

lines.sort(key=itemgetter(1))
grouped_photos = {c: list(p) for c, p in groupby(lines, itemgetter(1))}
  • 我使用dict解析只是作为groupby()返回的临时存储,以后不再需要它。*

1.现在我们需要按日期对同一个城市的列表进行排序。比较存储在string * 中的日期的常用方法(排序所必需的)是使用datetime.strptime()datetime.fromisoformat()(如果string与标准格式匹配)初始化datetime对象。

from datetime import datetime

...

grouped_photos["Warsaw"].sort(key=lambda x: datetime.fromisoformat(x[2]))

但是我们也可以利用python用来比较序列的lexicographic_order(字符串也是序列),这意味着我们不需要修改我们的日期字符串,就保持它的原样。

grouped_photos["Warsaw"].sort(key=itemgetter(2))

因此,基本上我们需要对grouped_photos中的每个值进行排序:

for value in grouped_photos.values():
    value.sort(key=itemgetter(2))

1.要生成新文件名并将其按原始顺序排列,首先需要存储原始列表索引。为此,我们应修改初始数据拆分,使其也包含行索引:

lines = [s.split(", ") + [i] for i, s in enumerate(string.splitlines())]

结果列表的大小将与源代码中的大小完全相同,因此为了不再使用排序,我们可以将结果列表初始化为长度与lines相同的None值列表,然后迭代grouped_photos并将生成的文件名保存到初始索引。
要生成文件名,我们需要城市的名称,在排序列表中的索引和原始文件扩展名。要从文件名中提取文件扩展名,我们可以使用splitext()或简单地调用str.rsplit()

from os.path import splitext

ext = splitext("pisatower.jpg")[1]
# OR
ext = "." + "pisatower.jpg".rsplit(".", 1)[1]

让我们恢复原始顺序并设置新文件名:

from os.path import splitext

...

result = [None] * len(lines)
for photos in grouped_photos.values():
    for i, (name, city, _, index) in enumerate(photos, 1):
        result[index] = f"{city}{i}{splitext(name)[1]}"

剩下的就是索引的补零了。列表的长度是一个最大的索引,所以我们可以使用每个列表的长度的字符串长度来获得最大的宽度。有很多方法可以填充数字,我将在这个例子中使用扩展格式语法:

for photos in grouped_photos.values():
    padding = len(str(len(photos)))
    for i, (name, city, _, index) in enumerate(photos, 1):
        result[index] = f"{city}{i:0{padding}}{splitext(name)[1]}"

现在我们需要把所有的代码组合在一起。利用循环的常识和基本知识,我们可以把上面的代码和某些优化组合在一起:

from operator import itemgetter
from itertools import groupby
from os.path import splitext

string = """photo.jpg, Warsaw, 2013-09-05 14:08:15
john.png, London, 2015-06-20 15:13:22
myFriends.png, Warsaw, 2013-09-05 14:07:13
Eiffel.jpg, Paris, 2015-07-23 08:03:02
pisatower.jpg, Paris, 2015-07-22 23:59:59
BOB.jpg, London, 2015-08-05 00:02:03
notredame.png, Paris, 2015-09-01 12:00:00
me.jpg, Warsaw, 2013-09-06 15:40:22
a.png, Warsaw, 2016-02-13 13:33:50
b.jpg, Warsaw, 2016-01-02 15:12:22
c.jpg, Warsaw, 2016-01-02 14:34:30
d.jpg, Warsaw, 2016-01-02 15:15:01
e.png, Warsaw, 2016-01-02 09:49:09
f.png, Warsaw, 2016-01-02 10:55:32
g.jpg, Warsaw, 2016-02-29 22:13:11"""

lines = [s.split(", ") + [i] for i, s in enumerate(string.splitlines())]
lines.sort(key=itemgetter(1, 2))
result = [None] * len(lines)
for city, [*photos] in groupby(lines, itemgetter(1)):
    padding = len(str(len(photos)))
    for i, (name, _, _, index) in enumerate(photos, 1):
        result[index] = f"{city}{i:0{padding}}{splitext(name)[1]}"

我注意到你没有在代码中使用任何导入,也许是因为一些奇怪的需求,所以下面是没有导入和语法糖的相同代码:

string = """photo.jpg, Warsaw, 2013-09-05 14:08:15
john.png, London, 2015-06-20 15:13:22
myFriends.png, Warsaw, 2013-09-05 14:07:13
Eiffel.jpg, Paris, 2015-07-23 08:03:02
pisatower.jpg, Paris, 2015-07-22 23:59:59
BOB.jpg, London, 2015-08-05 00:02:03
notredame.png, Paris, 2015-09-01 12:00:00
me.jpg, Warsaw, 2013-09-06 15:40:22
a.png, Warsaw, 2016-02-13 13:33:50
b.jpg, Warsaw, 2016-01-02 15:12:22
c.jpg, Warsaw, 2016-01-02 14:34:30
d.jpg, Warsaw, 2016-01-02 15:15:01
e.png, Warsaw, 2016-01-02 09:49:09
f.png, Warsaw, 2016-01-02 10:55:32
g.jpg, Warsaw, 2016-02-29 22:13:11"""

grouped_photos = {}
for i, line in enumerate(string.splitlines()):
    splitted = line.split(", ") + [i]
    city = splitted[1]
    if city in grouped_photos:
        grouped_photos[city].append(splitted)
    else:
        grouped_photos[city] = [splitted]

result = [None] * (i + 1)
for photos in grouped_photos.values():
    photos.sort(key=lambda x: x[2])
    padding = len(str(len(photos)))
    for i, (name, city, _, index) in enumerate(photos, 1):
        result[index] = city + str(i).zfill(padding) + "." + name.rsplit(".", 1)[1]

print(*result, sep="\n")添加到任何版本,以在控制台中获得输出。
输出:

Warsaw02.jpg
London1.png
Warsaw01.png
Paris2.jpg
Paris1.jpg
London2.jpg
Paris3.png
Warsaw03.jpg
Warsaw09.png
Warsaw07.jpg
Warsaw06.jpg
Warsaw08.jpg
Warsaw04.png
Warsaw05.png
Warsaw10.jpg

相关问题