Python 对项目进行排序,但防止相同的命名项目相邻;同时在集合中添加随机化
我正试图找出创建“最近”列表需要使用哪些排序算法,但要防止同名项彼此相邻,而且还要能够在集合中随机排列 例如,如果我们有以下原始数据:Python 对项目进行排序,但防止相同的命名项目相邻;同时在集合中添加随机化,python,list,algorithm,orders,Python,List,Algorithm,Orders,我正试图找出创建“最近”列表需要使用哪些排序算法,但要防止同名项彼此相邻,而且还要能够在集合中随机排列 例如,如果我们有以下原始数据: Apple 10/02/2020 Apple 15/02/2020 Apple 10/03/2020 Apple 15/03/2020 Apple 10/04/2020 Apple 15/04/2020 Banana 16/03/2020 Banana 21/03/2020 Banana 16/04/2020 Orange 13/
Apple 10/02/2020
Apple 15/02/2020
Apple 10/03/2020
Apple 15/03/2020
Apple 10/04/2020
Apple 15/04/2020
Banana 16/03/2020
Banana 21/03/2020
Banana 16/04/2020
Orange 13/03/2020
Orange 15/03/2020
我想对其进行排序,使其大致类似于下面显示的数据(每个项目名称中最新的项目)。当然,我们的橙子和香蕉都用完了,所以最后4个项目都必须是苹果,但这是没办法的
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Banana 21/03/2020
Apple 10/04/2020
Orange 13/03/2020
Banana 16/03/2020
Apple 15/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
问题:重复的“群体”
这个排序顺序的唯一问题是我们有一组重复的香蕉
,苹果
,橙色
。因此,我们希望有选择地将一组按某种随机顺序进行排序。“组”的大小将由我们选择的数字定义;不是按项目的数量
因此,如果我们将“组”设置为3,它将查看上述顺序,并将每组3随机化,因此看起来像:
Orange 15/03/2020
Apple 15/04/2020
Banana 16/04/2020
---
Banana 21/03/2020
Orange 13/03/2020
Apple 10/04/2020
---
Banana 16/03/2020
Apple 15/03/2020
Apple 10/03/2020
---
Apple 10/02/2020
Apple 15/02/2020
问题:丢失了“最近的”。
上面的排序组的问题是最近的项目被随机放在第一组的底部;当然,情况并非总是如此,但在本例中,情况一直如此
也许有一种方法可以保持第一组的顺序,或者随机化下面的组,或者只是重新排序,这样组的顺序就不同于前一组的顺序;例如:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
---
Apple 10/04/2020
Orange 13/03/2020
Banana 21/03/2020
---
Banana 16/03/2020
Apple 15/03/2020
Apple 10/03/2020
---
Apple 15/02/2020
Apple 10/02/2020
或
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
---
Banana 21/03/2020
Orange 13/03/2020
Apple 10/04/2020
---
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
---
Apple 10/02/2020
Apple 15/02/2020
我不完全确定我是否理解整个问题,但我想我得到了“最新的项目,但没有相同的项目出现在彼此旁边”,所以我将重点关注这一部分 如果你能把相同的项目分开,同时保持它们之间的顺序,那就很容易了;首先按日期排序,然后进行分离。我想不出一个可以实现这种分离的现有函数,所以我将一个“足够好”的函数拼凑在一起,以产生合理的输出:
from datetime import datetime
from typing import Any, Callable, List, Optional, TypeVar
_I = TypeVar('_I')
def declump(
items: List[_I],
key: Optional[Callable[[_I], Any]] = None
) -> None:
"""
Separate identical items by doing repeated swaps of the form:
AAB -> ABA (in-place)
Existing ordering is preserved within sets of identical items,
but not between non-identical items.
fixme: we can end up with a clump at the very end of the list!
Easy workaround is to reverse the list and declump again.
"""
if key is None:
key = lambda x: x
i = 0
key(items[i])
while i < len(items) - 2:
if (
key(items[i]) == key(items[i+1])
and key(items[i+1]) != key(items[i+2])
):
items[i+1], items[i+2] = items[i+2], items[i+1]
if i > 0:
i -= 1
continue
i += 1
produce = [
('Apple', '10/02/2020'),
('Apple', '15/02/2020'),
('Apple', '10/03/2020'),
('Apple', '15/03/2020'),
('Apple', '10/04/2020'),
('Apple', '15/04/2020'),
('Banana', '16/03/2020'),
('Banana', '21/03/2020'),
('Banana', '16/04/2020'),
('Orange', '13/03/2020'),
('Orange', '15/03/2020'),
]
produce.sort(key=lambda t: datetime.strptime(t[1], r'%d/%m/%Y'), reverse=True)
produce.reverse()
declump(produce, key=lambda t: t[0])
produce.reverse()
declump(produce, key=lambda t: t[0])
print('\n'.join(t[0].ljust(8) + t[1] for t in produce))
我几乎可以肯定有更好的方法来编写
dectlup
函数,但是翻转它并再次调用它似乎弥补了它的不足,因此我将把改进留给读者作为练习。我决定将其视为按日期对单个水果进行排序,然后将它们交错排列。
如果我将每个fruitdate设置为在时间上依赖于下一个fruitdate,但在相同的结果之间只有时间依赖关系B;然后可用于将项目划分为不同水果的子组,如上所述。然后我可以按时间顺序排列第一组,然后随机排列其他子组
守则:
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 29 09:21:15 2020
Answer to:
https://stackoverflow.com/questions/61485884/sorting-items-but-preventing-same-named-items-being-next-to-eachother-also-addi
@author: Paddy3118
"""
from random import shuffle
from functools import reduce
def toposort2(data):
"Based on: http://rosettacode.org/wiki/Topological_sort#Python"
for k, v in data.items():
v.discard(k) # Ignore self dependencies
extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys())
data.update({item:set() for item in extra_items_in_deps})
while True:
ordered = set(item for item,dep in data.items() if not dep)
if not ordered:
break
#yield ' '.join(sorted(ordered)) ## The one change!!
yield sorted(ordered)
data = {item: (dep - ordered) for item,dep in data.items()
if item not in ordered}
assert not data, "A cyclic dependency exists amongst %r" % data
#%%
raw = """
Apple 10/02/2020
Apple 15/02/2020
Apple 10/03/2020
Apple 15/03/2020
Apple 10/04/2020
Apple 15/04/2020
Banana 16/03/2020
Banana 21/03/2020
Banana 16/04/2020
Orange 13/03/2020
Orange 15/03/2020
"""
def fruit_yearmonthday(fruitdate):
"Order fields, (esp. dates), for item sorting"
fruit, date = fruitdate
d, m, y = date.split('/')
return fruit, y, m, d
def ymd(fruitdate_string):
"Order order field dates for partial order sorting"
fruit, date = fruitdate_string.split()
d, m, y = date.split('/')
return y, m, d
#%%
# raw data into individual (frit, date) ruples
items = [tuple(line.split()) for line in raw.strip().split('\n')]
# [('Apple', '10/02/2020'), ...]
# Order by date of each fruit kind
items.sort(key=fruit_yearmonthday)
# [('Apple', '10/02/2020'),
# ('Apple', '15/02/2020'),
# ('Apple', '10/03/2020'),
# ('Apple', '15/03/2020'),
# ('Apple', '10/04/2020'),
# ('Apple', '15/04/2020'),
# ('Banana', '16/03/2020'),
# ('Banana', '21/03/2020'),
# ('Banana', '16/04/2020'),
# ('Orange', '13/03/2020'),
# ('Orange', '15/03/2020')]
# Stringify
items = [f"{i[0]:6} {i[1]}" for i in items]
# Initial time-based dependencies only between _same_ fruits
last = items[0]
depends = {}
for fruitdate in items[1:]:
if last[0] == fruitdate[0]:
depends[last] = {fruitdate}
last = fruitdate
partial_order = list(toposort2(depends))
#print("Partial ordering. items on same line could be in any order:\n")
#print ('\n'.join(str(line) for line in partial_order))
# ['Apple 15/04/2020', 'Banana 16/04/2020', 'Orange 15/03/2020']
# ['Apple 10/04/2020', 'Banana 21/03/2020', 'Orange 13/03/2020']
# ['Apple 15/03/2020', 'Banana 16/03/2020']
# ['Apple 10/03/2020']
# ['Apple 15/02/2020']
# ['Apple 10/02/2020']
# An ordering:
# First line by date, then other lines *randomly*
order = []
for linenum, line in enumerate(partial_order):
if linenum == 0:
order += sorted(line, key=ymd, reverse=True)
else:
shuffle(line)
order += line
print("\nAN ORDERING OF ITEMS:")
for item in order:
print(f' {item}')
几次测试表明,前三项和后三项总是相同的,但第四项到第六项是随机的,第七项到第八项也是随机的
样本运行:
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Apple 10/04/2020
Banana 21/03/2020
Orange 13/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Orange 13/03/2020
Banana 21/03/2020
Apple 10/04/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Banana 21/03/2020
Apple 10/04/2020
Orange 13/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Apple 10/04/2020
Orange 13/03/2020
Banana 21/03/2020
Banana 16/03/2020
Apple 15/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Orange 13/03/2020
Apple 10/04/2020
Banana 21/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
你为什么不考虑像苹果香蕉苹果橙苹果香蕉这样的订单?你能澄清你的意思吗?如果你想要一个随机的顺序,当然他们不会再被最近的排序了。如果你所关心的只是将项目分成不同的组,那么就按组对其进行排序,然后按最新的组对第一组进行排序?也许你尝试过的一个例子会对你有所帮助。@billy因为我想获得尽可能多的独特项目的最新信息,否则在某些列表中,它会在显示其他项目之前在两个项目之间切换太长时间。@r.ook我在我的帖子中提到了组,通过对项目进行排序,然后将其分为多个组(在我的示例中,我选择了3个组的大小),并仅对组应用随机性,以使每个显示的组看起来更独特。您的原始数据类型是什么?纯文本<代码>数据帧?其他一些…?我们第一次看到橙色的问题是,在第8项中,如果我们将数据拆分/显示为3组,例如,我们的前3组都将显示两个苹果。不将相同的项目显示在一起的重要性随着“分组”的深入而变得越来越不重要,因此在列表的末尾有4个苹果基本上是可以的。
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Apple 10/04/2020
Banana 21/03/2020
Orange 13/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Orange 13/03/2020
Banana 21/03/2020
Apple 10/04/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Banana 21/03/2020
Apple 10/04/2020
Orange 13/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Apple 10/04/2020
Orange 13/03/2020
Banana 21/03/2020
Banana 16/03/2020
Apple 15/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020
runcell(2, 'C:/Users/Paddy3118/Google Drive/Code/fruit_orderings.py')
AN ORDERING OF ITEMS:
Banana 16/04/2020
Apple 15/04/2020
Orange 15/03/2020
Orange 13/03/2020
Apple 10/04/2020
Banana 21/03/2020
Apple 15/03/2020
Banana 16/03/2020
Apple 10/03/2020
Apple 15/02/2020
Apple 10/02/2020