【问题标题】:Recursively checking if value is in dictionary list递归检查值是否在字典列表中
【发布时间】:2017-02-02 17:09:53
【问题描述】:

我有以下格式的数据:

lsta = [[0,1], [0,2], [1,3], [2,4], [3,5], [4,6], [5,7], [7,9], [8,10], [8,11], [10,12], [11,13], [11,14], [12,15], [12,16], [6,17], [8,17]]

我试图根据它们是否连接将数据分成两个列表,所以我想您可以将数据视为图表。 目前,我有一个递归函数,它将按顺序跟踪数据[0,1] -> [1,3] -> [3,5] 等。

但是,当编号不按顺序排列时,就会出现问题;例如,6、17 和 8 是连接的,但由于原始数据的格式,这将被拆分为多个列表。我对此的预期解决方案是在序列的后续用尽后执行检查,以查看是否在字典中的其他任何位置(不仅仅是键)找到该值,如果是这样,该函数将从该点继续执行。不幸的是,我不能让它工作,建议表示赞赏。

下面的当前代码,“检查”功能当前没有按预期执行。

from collections import defaultdict


def split(items):
    # create lookup
    lookup = defaultdict(set)
    for k, v in items:
        lookup[k].add(v)

    results = []
    while sum(map(len, lookup.values())):
        # get first element from remaining items
        first_k = min((k for k in lookup if len(lookup[k])))
        first = first_k, min(lookup[first_k])

        # follow that element
        results.append(follow(first, lookup))

    return results

def follow(item, lookup):
    item_k, item_v = item
    lookup[item_k].remove(item_v)

    result = [item]
    # loop through all follow-up items (if any)
    for next_item in sorted(lookup[item_v]):
        # recursively follow the follow-up item
        result.extend(follow((item_v, next_item), lookup))
        try:
            #check if v appears in v of another key
            result.extend(check((item_v, next_item), lookup))
        except KeyError:
            break
    return result

def check(item, lookup):
    itm_k, itm_v = item
    rsult = []

    if itm_v in lookup.values():
        #if it appears again, follow item
        rsult.extend(follow((itm_k, next_item), lookup))
    return rsult



def test(items):
    for x in split(items):
        print(x)


lsta = [
    [ 0, 1],  [ 0, 2],  [ 1, 3],  [ 2, 4],
    [ 3, 5],  [ 4, 6],  [ 5, 7],  [ 7, 9],
    [ 8, 10], [ 8, 11], [10, 12], [11, 13],
    [11, 14], [12, 15], [12, 16], [ 6, 17],
    [ 8, 17],
]

test(lsta)

期望的输出是:

results = ([[0,1], [1,3], [3,5], [5,7], [7,9]], [[0,2], [2,4], [4,6], [6,17], [8,17], [8,10], [8,11], [11,13], [11,14], [10,12], [12,15], [12,16]])

【问题讨论】:

  • 您的预期输出包含 [8,17]、[8,10] 与给出的描述不匹配?
  • 我已编辑您的帖子以重新格式化代码。请确认我的说法正确 - 缩进非常重要!
  • 所以在 [6,17] 它找不到任何以 6 开头的键,所以会寻找与值匹配的元素 [8,17] ,然后它不会找到任何键17 所以会寻找那些匹配 [8,17], 8 的键,然后继续。希望这能有所澄清。
  • 看起来正确,谢谢@AustinHastings
  • 因此,如果我理解正确,您希望将您的配对分成两组(连接图),并且如果您遇到一对在其中一个集合中没有节点的配对已经找到,您将遵循未来的配对,直到您找到其中一组中的笔记?

标签: python dictionary recursion


【解决方案1】:

我建议您退后一步,以不同的方式思考您的问题。根据您的问题,您正在尝试识别 lsta 对列表中的连接子图。根据您的说法,这些图是简单连接的 - 也就是说,(a,b) 与 (b,a) 相同,没有方向性

查看前两对,您有0,10,2。这会产生一个由{0,1,2} 组成的子图,因为您并不真正关心哪一端是常见的。 set 类型将是您解决方案的关键。与其担心递归,不如尝试管理集合以获得您想要的结果。

首先,导入集合,然后创建您的默认字典。您不需要直接导入 defaultdict,因为您只需要输入一次,这会稍微清理一下:

import collections

Subgraphs = collections.defaultdict(set)

现在让我们添加您的初始测试数据。 请注意:这里有一个“错误”,因为最后一对 (8,17) 将子图连成一个。你可能不希望这样。

lsta = [
    [ 0, 1],  [ 0, 2],  [ 1, 3],  [ 2, 4],
    [ 3, 5],  [ 4, 6],  [ 5, 7],  [ 7, 9],
    [ 8, 10], [ 8, 11], [10, 12], [11, 13],
    [11, 14], [12, 15], [12, 16], [ 6, 17],
    [ 8, 17],
]

现在让我们初始化集合。每个 node(整数)将指向它所连接的集合。最初,节点只连接到自己,因此每个键 K 将指向一个集合 {K}

for a,b in lsta:
    Subgraphs[a].add(a)
    Subgraphs[b].add(b)

现在让我们合并集合。每对(a,b) 表示ab 已连接。这意味着这两个节点应该共享 same 节点集,因为它们(通过彼此)连接到所有邻居的联合。

我们假设节点 A 指向一个集合,并且该集合中的所有节点指向同一个集合。 (这有点儿 Python 技巧。它们不是同一集合的 副本,而是对内存中相同对象的实际 引用。)这意味着更新集合可以一次性完成,影响所有成员。

for a,b in lsta:
    seta = Subgraphs[a]
    setb = Subgraphs[b]
    others = setb - seta
    seta |= setb
    print("Processing (%d, %d): %s" % (a, b, seta))

    print("... updating: ", others)
    for o in others:
        Subgraphs[o] = seta

此时,Subgraphs 字典中的所有键(节点)都应指向包含其所有可达邻居的集合。我们将打印输入和结果数据,然后交给您。

print("\n***********")
print(lsta)
print(Subgraphs)

您可能想要删除最后一对:[8,17]。此外,您可能想要识别唯一的子图。我不知道你在用这段代码做什么,但如果你真的需要子图,你可以把它们变成 frozenset 对象,然后可以将其添加到 set 以产生不同的集合。或者,您可以只迭代 Subgraphs dict 的键,将集合合并到 seen 集合中并跳过 seen 中已有的任何键。

这是我使用 lsta 数据原样运行它时得到的输出:

Processing (0, 1): {0, 1}
... updating:  {1}
Processing (0, 2): {0, 1, 2}
... updating:  {2}
Processing (1, 3): {0, 1, 2, 3}
... updating:  {3}
Processing (2, 4): {0, 1, 2, 3, 4}
... updating:  {4}
Processing (3, 5): {0, 1, 2, 3, 4, 5}
... updating:  {5}
Processing (4, 6): {0, 1, 2, 3, 4, 5, 6}
... updating:  {6}
Processing (5, 7): {0, 1, 2, 3, 4, 5, 6, 7}
... updating:  {7}
Processing (7, 9): {0, 1, 2, 3, 4, 5, 6, 7, 9}
... updating:  {9}
Processing (8, 10): {8, 10}
... updating:  {10}
Processing (8, 11): {8, 10, 11}
... updating:  {11}
Processing (10, 12): {8, 10, 11, 12}
... updating:  {12}
Processing (11, 13): {8, 10, 11, 12, 13}
... updating:  {13}
Processing (11, 14): {8, 10, 11, 12, 13, 14}
... updating:  {14}
Processing (12, 15): {8, 10, 11, 12, 13, 14, 15}
... updating:  {15}
Processing (12, 16): {16, 8, 10, 11, 12, 13, 14, 15}
... updating:  {16}
Processing (6, 17): {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}
... updating:  {17}
Processing (8, 17): {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
... updating:  {0, 1, 2, 3, 4, 5, 6, 7, 9, 17}

*********
LSTA:  [[0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [7, 9], [8, 10], [8, 11], [10, 12], [11, 13], [11, 14], [12, 15], [12, 16], [6, 17], [8, 17]]
Subgraphs:  defaultdict(<class 'set'>, {0: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 1: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 2: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 3: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 4: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 5: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 6: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 7: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 8: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 9: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 10: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 11: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 12: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 13: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 14: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 15: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 16: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 17: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}})

这是我从 lsta 中删除 [8,17] 对时的结果:

Processing (0, 1): {0, 1}
... updating:  {1}
Processing (0, 2): {0, 1, 2}
... updating:  {2}
Processing (1, 3): {0, 1, 2, 3}
... updating:  {3}
Processing (2, 4): {0, 1, 2, 3, 4}
... updating:  {4}
Processing (3, 5): {0, 1, 2, 3, 4, 5}
... updating:  {5}
Processing (4, 6): {0, 1, 2, 3, 4, 5, 6}
... updating:  {6}
Processing (5, 7): {0, 1, 2, 3, 4, 5, 6, 7}
... updating:  {7}
Processing (7, 9): {0, 1, 2, 3, 4, 5, 6, 7, 9}
... updating:  {9}
Processing (8, 10): {8, 10}
... updating:  {10}
Processing (8, 11): {8, 10, 11}
... updating:  {11}
Processing (10, 12): {8, 10, 11, 12}
... updating:  {12}
Processing (11, 13): {8, 10, 11, 12, 13}
... updating:  {13}
Processing (11, 14): {8, 10, 11, 12, 13, 14}
... updating:  {14}
Processing (12, 15): {8, 10, 11, 12, 13, 14, 15}
... updating:  {15}
Processing (12, 16): {16, 8, 10, 11, 12, 13, 14, 15}
... updating:  {16}
Processing (6, 17): {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}
... updating:  {17}

*********
LSTA:  [[0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [7, 9], [8, 10], [8, 11], [10, 12], [11, 13], [11, 14], [12, 15], [12, 16], [6, 17]]
Subgraphs:  defaultdict(<class 'set'>, {0: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 1: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 2: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 3: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 4: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 5: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 6: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 7: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 8: {16, 8, 10, 11, 12, 13, 14, 15}, 9: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}, 10: {16, 8, 10, 11, 12, 13, 14, 15}, 11: {16, 8, 10, 11, 12, 13, 14, 15}, 12: {16, 8, 10, 11, 12, 13, 14, 15}, 13: {16, 8, 10, 11, 12, 13, 14, 15}, 14: {16, 8, 10, 11, 12, 13, 14, 15}, 15: {16, 8, 10, 11, 12, 13, 14, 15}, 16: {16, 8, 10, 11, 12, 13, 14, 15}, 17: {0, 1, 2, 3, 4, 5, 6, 7, 17, 9}})

【讨论】:

  • 感谢您的详细回复。我想我应该增加一些清晰度,也许也改写原来的问题。该算法的实际最终结果是在给定点将一个图拆分为两个图。这个数据来自的图表是graph,如果你不看我在绘画中所做的糟糕的快速工作。因此,我最初的方法是,尽管我非常愿意改变我的方向(我对 python 和编程很陌生)。
猜你喜欢
  • 2019-02-13
  • 1970-01-01
  • 2011-04-23
  • 2017-09-28
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 2018-12-08
相关资源
最近更新 更多