【问题标题】:Finding a circular path in a list of dicts (Python)在字典列表中查找循环路径(Python)
【发布时间】:2021-01-19 17:27:46
【问题描述】:

我的数据看起来像这样

mydict = [
    {"id": 0, "item_total": 10000, "send_to_id": None},
    {"id": 1, "item_total": 15000, "send_to_id": None},
    {"id": 2, "item_total": 30000, "send_to_id": 1},
    {"id": 3, "item_total": 20000, "send_to_id": None},
...
]

其中 id 始终是字典在列表中的位置。

item_totals 将被聚合,“send_to_id”键会影响聚合的发生方式。在这里,由于“id”= 2 的 dict 具有“send_to_id”= 1,因此“id”= 1 的 dict 就是我所说的目标层,这两个项目的总数将与正常情况不同地聚合。

不允许的是这样的循环,其中第 1 项指向第 2 项,第 2 项指向第 1 项。

mydict = [
    {"id": 0, "item_total": 10000, "send_to_id": None},
    {"id": 1, "item_total": 15000, "send_to_id": 2},
    {"id": 2, "item_total": 30000, "send_to_id": 1},
    {"id": 3, "item_total": 20000, "send_to_id": None}
]

或者这个,它仍然是圆形的,需要三个步骤

mydict = [
    {"id": 0, "item_total": 10000, "send_to_id": None},
    {"id": 1, "item_total": 15000, "send_to_id": 3},
    {"id": 2, "item_total": 30000, "send_to_id": 1},
    {"id": 3, "item_total": 20000, "send_to_id": 2}
]

还有一个项目不能指向它自己。

我不知道该怎么做,但我想获取一个像上面这样的字典列表,并找出是否存在循环路径,以便我可以向用户提供适当的错误消息。任何人都可以帮忙吗? 我正在尝试找出如何找到下一个项目的路径,但它在我的大脑中打结。

如果重要的话,列表的最大长度约为 50。

谢谢!

【问题讨论】:

    标签: python list dictionary path circular-dependency


    【解决方案1】:

    一个好的第一步可能是创建一个仅包含地图的字典。我们可以用一个漂亮的dictionary comprehension 来做到这一点(看下面的第二个绿色代码示例块)。

    def get_direct_mappings(data: list) -> dict: 
        return {d["id"]: d["send_to_id"] for d in data if d["send_to_id"] is not None} 
    

    现在我们有一个稍微容易解决的问题,我们可以使用previously made solutions 来帮助我们。具体来说,我们基本上可以重复使用“Update”之后发布的解决方案,并将我们上面的代码添加到其中。

    def find_cycles(original_data: list) -> list:
        n = {d["id"]: d["send_to_id"] for d in original_data if d["send_to_id"] is not None}
        cycles = []
        while n:
            visited = {}
            count = 0
            k, v = n.popitem()
            while v is not None:
                # visited[k] = (count, v)
                visited[k] = count
                count += 1
                k = v
                v = n.pop(k, None)
    
            if k in visited:
                if len(visited) == 1:
                    cycle = tuple(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
    

    虽然它不是最漂亮的,但它确实有效。

    mydict = [
        {"id": 0, "item_total": 10000, "send_to_id": None},
        {"id": 1, "item_total": 15000, "send_to_id": 3},
        {"id": 2, "item_total": 30000, "send_to_id": 1},
        {"id": 3, "item_total": 20000, "send_to_id": 2}
    ]
    print(find_cycles(mydict))
    # prints [(1, 3, 2)]
    
    mydict = [
        {"id": 0, "item_total": 10000, "send_to_id": None},
        {"id": 1, "item_total": 15000, "send_to_id": 2},
        {"id": 2, "item_total": 30000, "send_to_id": 1},
        {"id": 3, "item_total": 20000, "send_to_id": None}
    ]
    print(find_cycles(mydict))
    # prints [(1, 2)]
    
    mydict = [
        {"id": 0, "item_total": 10000, "send_to_id": None},
        {"id": 1, "item_total": 15000, "send_to_id": None},
        {"id": 2, "item_total": 30000, "send_to_id": 1},
        {"id": 3, "item_total": 20000, "send_to_id": None},
    ]
    print(find_cycles(mydict))
    # prints []
    

    【讨论】:

    • 哦,太棒了。我确实环顾四周,但不确定如何用谷歌搜索。谢谢!
    猜你喜欢
    • 2017-12-04
    • 1970-01-01
    • 2017-12-27
    • 2021-12-14
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    相关资源
    最近更新 更多