递归检查值是否在字典列表中

时间:2017-02-02 17:09:53

标签: python dictionary recursion

我的数据格式为:

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但是由于原始数据的格式化,这将被分成多个列表。我对此的预期解决方案是在序列的以下用完之后执行检查,以查看是否在字典中的任何其他位置(而不仅仅是键)找到该值,如果是,则该函数将从该点继续跟随。不幸的是,我无法让它工作,建议赞赏。

下面的当前代码,'check'功能目前是没有按预期执行的位。

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]])

1 个答案:

答案 0 :(得分: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],
]

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

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

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

我们假设节点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}})