在字典中查找循环

时间:2019-06-19 04:19:58

标签: python

我有一本字典,其值为:

m = {1: 2, 7: 3, 2: 1, 4: 4, 5: 3, 6: 9}

所需的输出应为循环值,例如1:2-> 2:1 = cycle,两者都存在于字典中。 4:4也是一个循环。

我的输出应该是

[(1, 2), [4]]

代码

m = {1: 2, 7: 3, 2: 1, 4: 4, 5: 3, 6: 9}
k = list(m.items())
print(k)

p = [t[::-1] for t in k]
print(p)

my_list = [(a, b) for (a, b) in p for (c, d) in k  if ((a ==c) and (b == d))]

for i in k:
     if i in my_list:
             print("cycles : ", i)

输出:

我得到的输出是

cycles : (1, 2)
cycles : (2, 1)
cycles : (4, 4)

有人可以帮我吗?

2 个答案:

答案 0 :(得分:2)

让我们将其分为两个步骤。首先,我们将找到循环。然后,我们将根据需要格式化输出。

假设您有字典,查找周期就很容易:值成为键,使查找快速。我们可以按顺序将循环存储在一组中,以避免重复:

cycles = set()
for k, v in m.items():
    if m.get(v) == k:
        cycles.add(tuple(sorted((k, v))))

并非我建议这样做,但是以上内容可以写成难以理解的单线:

cycles = set(tuple(sorted(item)) for item in m.items() if m.get(item[1]) == item[0])

现在要格式化数据。您需要一个列表输出,以及具有重复格式为列表的重复项:

output = [[k] if k == v else (k, v) for k, v in cycles]

如果您不喜欢干净的代码,可以想像如何将整个操作转换为单行代码:)

更新

值得考虑的情况是周期长于一个或两个条目。您似乎只想每个周期存储一个元素,所以让我们开始吧。我们可以遵循字典中每个元素的链。如果链中的任何部分构成一个周期,我们可以找到要报告的周期的最小元素,并删除所有已访问的元素,因为它们不再在考虑之列:

def find_cycles(m):
    n = m.copy()  # don't mutilate the original
    cycles = []
    while n:
        visited = {}
        count = 0
        k, v = n.popitem()
        while v is not None:
            visited[k] = (count, v)
            count += 1
            k = v
            v = n.pop(k, None)

        if k in visited:
            cycle_start = visited[k][0]
            item = min((k, v) for k, (c, v) in visited.items() if c >= cycle_start)
            cycles.append(item)

    return [[k] if k == v else (k, v) for k, v in cycles]

例如:

>>> find_cycles({1:2, 2:3, 3:4, 4:5, 5:1, 6:1, 7:1, 8:8})
[(1, 2), [8]]

更好的概括可能是返回一个包含整个循环的元组,从最小的键开始。通常,if k in visited:下的语句需要进行更改:

    visited[k] = count
    ...
    if k in visited:
        if len(visited) == 1:
            cycle = list(visited.keys())
        else:
            cycle_start = visited[k]
            cycle = sorted((c, k) for k, c in visited.items() if c >= cycle_start)
            cycle = tuple(k for c, k in cycle)
            k = min(range(len(cycle)), key=lambda x: cycle[x])
            cycle = cycle[k:] + cycle[:k]
       cycles.append(cycle)

return cycles

此版本提供更多信息:

>>> find_cycles({1:2, 2:3, 3:4, 4:5, 5:1, 6:1, 7:1, 8:8})
[(1, 2, 3, 4, 5), [8]]

如果您对此感兴趣,这里是我的IDEOne暂存空间:https://ideone.com/6kpRrW

答案 1 :(得分:0)

已编辑 嘿,一旦找到对,您就必须用列表中的其他任何符号替换对。然后它会为您提供所需的结果。

map = {1:2, 7:3, 2:1, 4:4, 5:3, 6:9}

k = list(map.items())

print(k)

result = []

for i in k:
    if i != -1 and i[::-1] in k:
        result.append((set(i)))
        k[k.index(i[::-1])] = -1

print(result)
#if you want tuples as output
[print(tuple(x),end = " ") for x in result]