如何在Python中加入链接以获得循环?
我有一个链接列表,想知道连接的路径/循环 我的链接如下所示:如何在Python中加入链接以获得循环?,python,list,functional-programming,iterator,reduce,Python,List,Functional Programming,Iterator,Reduce,我有一个链接列表,想知道连接的路径/循环 我的链接如下所示: [[0, 3], [1, 0], [3, 1]] 我希望答案是这样一个循环(或任何其他匹配循环): 因此,取第一个子列表的第一个元素,然后取第二个元素,然后查找以该元素开始的下一个子列表,然后重新开始 有没有一种优雅的方式来实现这一点?我尝试了reduce函数,但是必须以链接匹配的方式对链接进行排序。我想看看: 提供的功能和算法: 周期检测 把它变成一本字典,循环阅读 def get_cycles(links): ""
[[0, 3], [1, 0], [3, 1]]
我希望答案是这样一个循环(或任何其他匹配循环):
因此,取第一个子列表的第一个元素,然后取第二个元素,然后查找以该元素开始的下一个子列表,然后重新开始
有没有一种优雅的方式来实现这一点?我尝试了reduce函数,但是必须以链接匹配的方式对链接进行排序。我想看看:
提供的功能和算法:
- 周期检测
把它变成一本字典,循环阅读
def get_cycles(links):
"""Get a list of all cycles given a list of links"""
links_dict = dict(links)
ret = []
ret_sets = []
for starting_point in links_dict:
cycle = []
x = starting_point
while x != None:
cycle.append(x)
x = links_dict.get(x)
if x == starting_point:
break
# make sure the cycle is not a repeat (and was a cycle)
if x != None:
cycle_set = set(cycle)
if cycle_set not in ret_sets:
ret.append(cycle)
ret_sets.append(cycle_set)
return ret
assert get_cycles([[0, 3], [1, 0], [3, 1]]) == [[0, 3, 1]]
assert get_cycles([[0, 3], [1, 0], [3, 1], [5, 2]]) == [[0, 3, 1]]
assert get_cycles([[0, 3], [1, 0], [3, 1], [5, 2], [2, 5]]) == [[0, 3, 1], [2, 5]]
尝试此操作,假设链接列表中只存在一个循环:
def cycle_list(links):
d = dict(links)
ele = links[0][0]
nxt = d[ele]
lst = [ele]
seen = set(lst)
while nxt not in seen:
lst.append(nxt)
seen.add(nxt)
ele = nxt
nxt = d[ele]
return lst
以你的例子:
cycle_list([[0, 3], [1, 0], [3, 1]])
> [0, 3, 1]
如果链接列表中可能存在多个循环(你在问题中没有提到),那么最好使用David Robinson的答案。如果你知道有一个循环,并且所有链接都在循环中(或者至少没有“拆分”)在方向中,表示从任何给定点只有一条路,您可以使用以下方法:
def get_cycle(data):
d = dict(data)
first = data[0][0]
current = d[first]
path = [first]
while True:
if current == first:
return path
else:
path.append(current)
current = d[current]
它所做的是遍历给定的数据,从第一个链接的第一个点开始。然后它只跟随所有链接,直到到达路径的开头。当它到达路径的开头时,它返回路径
简单,而且我相信它相当有效。考虑使用该软件包:
输出:
>> [0, 3, 1]
使用发电机有一种非常优雅的方法:
def cycle(lst, val, stop=None):
d = dict(lst)
stop = stop if stop is not None else val
while True:
yield val
val = d.get(val, stop)
if val == stop: break
首先,它允许自然迭代:
>>> for x in cycle([[0, 3], [1, 0], [3, 1]], 0):
.... print x
....
0
3
1
其次,它允许轻松创建列表:
>>> list(cycle([[0, 3], [1, 0], [3, 1]], 0))
[0, 3, 1]
最终,它允许无限项生成:
>>> generator = cycle([[0, 3], [1, 0], [3, 1]], 0, Ellipsis)
>>> generator.next()
... 0
>>> generator.next()
... 3
>>> generator.next()
... 1
>>> generator.next()
... 0
>>> generator.next()
... 3
>>> generator.next()
... 1
>>> generator.next()
... 0
>>> generator.next()
... 3
使用itertools.permutations,这将获得一组唯一循环:
import itertools
g = [(0,3), (1,0), (3,1), (1,4), (4,3)]
cycles = {}
for edges in itertools.permutations(g):
start = prev = edges[0]
for i, edge in enumerate(edges[1:], start=1):
if prev[1] != edge[0]:
break
if edge[1] != start[0]:
prev = edge
continue
cycles.update({tuple(sorted(edges[0:i+1])): edges[0:i+1]})
break
result = []
for cycle in cycles.values():
result.append([edge[0] for edge in cycle])
print result
本例中的结果是
[[3,1,0],[4,3,1]]
导入中有一个输入错误。虽然我编写了一个很好的手动解决方案,但我+1这一次是因为networkx是一个美丽的野兽。这是我唯一一次在numpy之外看到有人使用省略号!我通常使用object()
。并不是说椭圆有什么问题:pElipsis作为一个哨兵值真的很好,因为几乎没有什么东西可以意外地变成它,而且它是一个不需要实例化的单子。此外,这对无限代人来说是有意义的。
>>> generator = cycle([[0, 3], [1, 0], [3, 1]], 0, Ellipsis)
>>> generator.next()
... 0
>>> generator.next()
... 3
>>> generator.next()
... 1
>>> generator.next()
... 0
>>> generator.next()
... 3
>>> generator.next()
... 1
>>> generator.next()
... 0
>>> generator.next()
... 3
import itertools
g = [(0,3), (1,0), (3,1), (1,4), (4,3)]
cycles = {}
for edges in itertools.permutations(g):
start = prev = edges[0]
for i, edge in enumerate(edges[1:], start=1):
if prev[1] != edge[0]:
break
if edge[1] != start[0]:
prev = edge
continue
cycles.update({tuple(sorted(edges[0:i+1])): edges[0:i+1]})
break
result = []
for cycle in cycles.values():
result.append([edge[0] for edge in cycle])
print result