从嵌套元组中提取数据

时间:2013-09-23 11:14:11

标签: python data-structures huffman-code

对于我正在处理的应用程序,我需要从嵌套元组创建列表,表示每个分支中包含的数据。

作为参考,元组代表一个霍夫曼树,例如:

tree = (1.0, (0.5, (0.25, (0.125, 'd'),(0.125, 'c')), (0.25, 'b')), (0.5,'a'))

这是从具有以下概率的霍夫曼例程创建的:

a:0.5, b:0.25, c:0.125, d:0.125

我想出一个看起来像

的列表
[['a'],['b','c','d']]

我尝试过以下代码:

def makeList(tree):
    if len(tree) == 2:
        return [tree[0]]
    else:
        rightlist = []
        leftlist = []
        right = list(tree[1])
        left = list(tree[2])
        for i in range(1, len(right)):
            rightlist.append(right[i])
        for i in range(1, len(left)):
            leftlist.append(left[i])
        return [rightlist, leftlist]

然而,这会返回

[['a'],[(0.25, (0.125, 'd'),(0.125,'c')),(0.25,'b')]

这不是我想要的。

我怎样才能修改上面的代码以产生我想要的输出?

修改

我已经制作了一些给出平衡输入的代码:

('a',0.25), ('b', 0.25), ('c', 0.25), ('d',0.25)

产生我想要的输出:

[['a','b'], ['c','d']]

def makeList(tree):
if len(tree) == 2:
    print("I'm in here")
    return [tree[1]]
else:
    right = tree[1]
    left = tree[2]
    rightlist = []
    leftlist = []

    for i in range(0, len(right)):
        if type(right[i]) == tuple:
            print('right: ' + str(right[i]))
            rightlist.append(right[i][1])

    for i in range(0, len(left)):
        if type(left[i]) == tuple:
            print('left: ' + str(left[i]))
            leftlist.append(left[i][1])

    return [rightlist, leftlist]

但是,它在以下输入(下面的输出)上失败:

exampleData = [(0.5, 'a'), (0.5,'b')]

[[],[[]]

exampleData = [(0.5, 'a'), (0.25,'b'), (0.25,'c')]

[[],['b'.'c']]

exampleData = [(0.5,'a'), (0.25,'b'), (0.125,'c'), (0.125,'d')]

[[]],['b',(0.125, 'd')]]

但是,需要通过的黄金标准测试是为随机树创建这些列表:

probs = np.random.dirichlet([1]*4).tolist()
indices = range(0,4)
exampleData = zip(probs, indices)
huffTree = makeHuffmanTree(exampleData)
groups = makeLists(groups)

3 个答案:

答案 0 :(得分:2)

我有一个递归的解决方案。

def makeListAndFlatten(tree):
    treeList = makeList(tree)
    branchA = treeList[0]
    branchB = treeList[1]
    flatA = flatten(branchA)
    flatB = flatten(branchB)
    return [flatA, flatB]

def makeList(tree):
    if len(tree) == 2:
        return tree[1]
    else:
        for i in range(1,len(tree)):
                return [tree[len(tree)-1][1], makeList(tree[i])]

def flatten(nestedList):
        def aux(listOrItem):
            if isinstance(listOrItem, list):
                for elem in listOrItem:
                    for item in aux(elem):
                        yield item
            else:
                yield listOrItem
        return list(aux(nestedList))

如果我们跑:

makeListAndFlatten(tree)

这给出了结果:

[['a'], ['b', 'c', 'd']]

包含两个列表的列表,其中包含两侧下部分支的叶子。

修改

此代码基于原始问题中给出的格式:

tree =(1.0,(0.5,(0.25,(0.125,'d'),(0.125,'c')),(0.25,'b')),(0.5,'a'))

如果输入格式被更改,那么这将无效。

答案 1 :(得分:1)

鉴于你已经拥有了这棵树,最多有两个分支:

import Queue

def leaves(tree):
    result = []
    queue = Queue.Queue()
    queue.put(tree)
    while not queue.empty():
        node = queue.get()
        if type(node[1]) == tuple:
            for subnode in node[1:]:
                queue.put(subnode)
        else:
            result.append(node[1])
    return result

def makeList(tree):
    if len(tree) == 2:
        return [tree[1]]

    left = tree[1]
    right = tree[2]
    return [leaves(left), leaves(right)]

这需要两个分支并抓住每个分支的叶子,丢弃每个叶子的前半部分。它使用广度优先搜索来避免递归问题。

我无法将exampleData列表转换为树来测试它们,但它适用于第一个问题。

答案 2 :(得分:0)

似乎是一般算法,你需要一个函数,它(1)计算下面树的总重量,然后(2)实现树旋转以旋转树,直到你得到平衡。也就是说,这在某种程度上只是标准树平衡算法的变体,除了对于AVL树,例如,你在平衡深度,这里你平衡数据本身的权重。