Python 给定一个完全由字符串元组列表表示的线性顺序,将该顺序作为字符串列表输出
给定形式为Python 给定一个完全由字符串元组列表表示的线性顺序,将该顺序作为字符串列表输出,python,Python,给定形式为[(a,b),…]的项目对,其中(a,b)表示a>b,例如: [('best','better'),('best','good'),('better','good')] 我想输出一个表单列表: ['best','better','good'] 出于某种原因,这很难做到。有什么想法吗 ============================代码============================= 我知道它为什么不起作用 def to_rank(raw): rank = [
[(a,b),…]
的项目对,其中(a,b)
表示a>b
,例如:
[('best','better'),('best','good'),('better','good')]
我想输出一个表单列表:
['best','better','good']
出于某种原因,这很难做到。有什么想法吗
============================代码=============================
我知道它为什么不起作用
def to_rank(raw):
rank = []
for u,v in raw:
if u in rank and v in rank:
pass
elif u not in rank and v not in rank:
rank = insert_front (u,v,rank)
rank = insert_behind(v,u,rank)
elif u in rank and v not in rank:
rank = insert_behind(v,u,rank)
elif u not in rank and v in rank:
rank = insert_front(u,v,rank)
return [[r] for r in rank]
# @Use: insert word u infront of word v in list of words
def insert_front(u,v,words):
if words == []: return [u]
else:
head = words[0]
tail = words[1:]
if head == v: return [u] + words
else : return ([head] + insert_front(u,v,tail))
# @Use: insert word u behind word v in list of words
def insert_behind(u,v,words):
words.reverse()
words = insert_front(u,v,words)
words.reverse()
return words
=========================更新===================
根据许多人的建议,这是一个直接的拓扑排序设置,我最终决定使用来自以下来源的代码:algocoding.wordpress.com/2015/04/05/topology-sorting-python/
这解决了我的问题
def go_topsort(graph):
in_degree = { u : 0 for u in graph } # determine in-degree
for u in graph: # of each node
for v in graph[u]:
in_degree[v] += 1
Q = deque() # collect nodes with zero in-degree
for u in in_degree:
if in_degree[u] == 0:
Q.appendleft(u)
L = [] # list for order of nodes
while Q:
u = Q.pop() # choose node of zero in-degree
L.append(u) # and 'remove' it from graph
for v in graph[u]:
in_degree[v] -= 1
if in_degree[v] == 0:
Q.appendleft(v)
if len(L) == len(graph):
return L
else: # if there is a cycle,
return []
RockBilly的解决方案也适用于我的情况,因为在我的设置中,对于每个v
(u,v)
。所以他的答案不是很“计算机科学”,但在这种情况下,它完成了工作 如果列表完整,意味着有足够的信息进行排名(也没有重复或冗余输入),这将起作用
from collections import defaultdict
lst = [('best','better'),('best','good'),('better','good')]
d = defaultdict(int)
for tup in lst:
d[tup[0]] += 1
d[tup[1]] += 0 # To create it in defaultdict
print sorted(d, key = lambda x: d[x], reverse=True)
# ['best', 'better', 'good']
只要给他们点,每次你在列表中遇到左一点,就增加左一点
编辑:我确实认为OP具有确定的输入类型。始终具有组合nCr(n,2)的元组计数。这是一个正确的解决方案。无需抱怨边缘案例,我已经知道了答案(并提到了)。您要找的是。您可以使用深度优先搜索(我链接的wiki中包含伪代码)在线性时间内完成此操作。如果您根据列表项进行排序或创建词典,您将错过@Rockybilly在其回答中提到的顺序。我建议您从原始列表的元组创建一个列表,然后删除重复项
def remove_duplicates(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
i = [(5,2),(1,3),(1,4),(2,3),(2,4),(3,4)]
i = remove_duplicates(list(x for s in i for x in s))
print(i) # prints [5, 2, 1, 3, 4]
j = [('excellent','good'),('excellent','great'),('great','good')]
j = remove_duplicates(list(x for s in j for x in s))
print(j) # prints ['excellent', 'good', 'great']
见参考资料:
有关
remove_duplicates()
函数的说明,请参见此。您可以利用以下事实:列表中排名最低的项永远不会出现在任何元组的开头。您可以提取此最低项,然后从列表中删除包含此最低项的所有元素,然后重复以获取下一个最低项
即使您有多余的元素,或者列表比这里的一些示例更稀疏,这也应该有效。我将其分解为寻找排名最低的项目,然后使用它创建最终排名的繁重工作
from copy import copy
def find_lowest_item(s):
#Iterate over set of all items
for item in set([item for sublist in s for item in sublist]):
#If an item does not appear at the start of any tuple, return it
if item not in [x[0] for x in s]:
return item
def sort_by_comparison(s):
final_list = []
#Make a copy so we don't mutate original list
new_s = copy(s)
#Get the set of all items
item_set = set([item for sublist in s for item in sublist])
for i in range(len(item_set)):
lowest = find_lowest_item(new_s)
if lowest is not None:
final_list.insert(0, lowest)
#For the highest ranked item, we just compare our current
#ranked list with the full set of items
else:
final_list.insert(0,set(item_set).difference(set(final_list)).pop())
#Update list of ranking tuples to remove processed items
new_s = [x for x in new_s if lowest not in x]
return final_list
list_to_compare = [('black', 'dark'), ('black', 'dim'), ('black', 'gloomy'), ('dark', 'gloomy'), ('dim', 'dark'), ('dim', 'gloomy')]
sort_by_comparison(list_to_compare)
[‘黑色’、‘暗淡’、‘黑暗’、‘阴郁’]
[“最好”、“更好”、“好”]
[“最好”、“更好”、“好”]
这里有一个方法。它基于使用完整的成对排序来生成一个旧式(早期Python 2)
cmp
函数,然后使用functools.cmp\u to\u key
将其转换为适合Python 3排序方法的键
:
import functools
def sortByRankings(rankings):
def cmp(x,y):
if x == y:
return 0
elif (x,y) in rankings:
return -1
else:
return 1
items = list({x for y in rankings for x in y})
items.sort(key = functools.cmp_to_key(cmp))
return items
测试结果如下:
ranks = [('a','c'), ('b','a'),('b','c'), ('d','a'), ('d','b'), ('d','c')]
print(sortByRankings(ranks)) #prints ['d', 'b', 'a', 'c']
请注意,要正确工作,参数
排名
必须包含每对不同项目的条目。如果没有,则在将其提供给此函数之前,首先需要计算所具有的对的传递闭包。如果指定了完整的语法,则可以简单地计算项目数:
>>> import itertools as it
>>> from collections import Counter
>>> ranks = [('best','better'),('best','good'),('better','good')]
>>> c = Counter(x for x, y in ranks)
>>> sorted(set(it.chain(*ranks)), key=c.__getitem__, reverse=True)
['best', 'better', 'good']
如果语法不完整,则可以构建一个图和dfs
所有路径来查找最长的路径。这并不是很低效,因为我还没有想过:):
我们可以假设您的输入列表是完整的吗?也就是说,它包含定义顺序所需的所有比较?似乎您需要首先计算传递闭包,可能使用Warshall算法,然后根据得到的总数进行排序order@AndrewGuy是的,这个假设是正确的。你认为元组列表会有多大?您正在寻找的算法的性能有多重要?@SimeonVisser Index很好,列表的平均长度为6。
排序(d)
将按键排序,而不是按数值排序。@SimeonVisser啊,请原谅我的无聊。@Rockybilly它适用于三项列表,但不适用于四项列表?例如:[('black','dark'),('black','dim'),('black','Dame'),('dark','dark'),('dim','Dally')]输出['black','dark','dim','Dally','Dally'],但是应该输出['black','dim','dark','Dally']@chibro2以前的版本是错误的,请再试一次。@Rockybilly明白了!谢谢,孩子,我从来没有想过这个解决办法。太优雅了。你把一件简单的事情提升到了一个新的水平!!你能解释一下这有多简单吗?我只是给出了他所问问题的名称。OP不需要拓扑排序或DFS!!这可以通过更简单的代码实现,而不是OP是否需要拓扑排序的问题。拓扑排序不是解决方案。这是他问的问题的名称。一个可能的解决方案是DFS。他当然不需要,但这是一个简单的方法。谢谢,将问题分类有时是最重要的步骤。我不认为这是他要求的。最后一个示例的输出应该是“优秀”、“更好”、“好”@LawrenceWu您在哪里找到了更好的?我的代码的输入是[('excellent','good'),('excellent','great'),('great','good')]
,答案是正确的。不要通过观察输出来判断解决方案,看代码。我的意思是“很棒”。是的,输出仍然错误。仔细阅读问题-如果元组(great,good)在输入中,那么great需要在good之前出现。OP没有提到这一点,我已经仔细阅读了问题。此外,好出现在伟大之前,因为好(第一次出现在元组1中)出现在伟大(第一次出现在元组2中)之前。我没有改变列表中的顺序,所以输出应该是正确的。这是目前唯一正确的答案(这是kahns算法的实现,尽管它可能不是线性时间实现)。接受这一点就好了。计数是解决问题的一种优雅而简单的方法
ranks = [('a','c'), ('b','a'),('b','c'), ('d','a'), ('d','b'), ('d','c')]
print(sortByRankings(ranks)) #prints ['d', 'b', 'a', 'c']
>>> import itertools as it
>>> from collections import Counter
>>> ranks = [('best','better'),('best','good'),('better','good')]
>>> c = Counter(x for x, y in ranks)
>>> sorted(set(it.chain(*ranks)), key=c.__getitem__, reverse=True)
['best', 'better', 'good']
def dfs(graph, start, end):
stack = [[start]]
while stack:
path = stack.pop()
if path[-1] == end:
yield path
continue
for next_state in graph.get(path[-1], []):
if next_state in path:
continue
stack.append(path+[next_state])
def paths(ranks):
graph = {}
for n, m in ranks:
graph.setdefault(n,[]).append(m)
for start, end in it.product(set(it.chain(*ranks)), repeat=2):
yield from dfs(graph, start, end)
>>> ranks = [('black', 'dark'), ('black', 'dim'), ('black', 'gloomy'), ('dark', 'gloomy'), ('dim', 'dark'), ('dim', 'gloomy')]
>>> max(paths(ranks), key=len)
['black', 'dim', 'dark', 'gloomy']
>>> ranks = [('a','c'), ('b','a'),('b','c'), ('d','a'), ('d','b'), ('d','c')]
>>> max(paths(ranks), key=len)
['d', 'b', 'a', 'c']