2013-09-23 214 views
0

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

,以供参考元组代表霍夫曼树,一个例子是:

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

这是不太我想要的。

我怎么能修改我的代码来产生我想要的输出?

EDIT

我已经产生一些代码,给定的一个平衡的输入:

('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) 
+0

这是实际的代码吗?我认为这是len不是长度,for循环最后需要冒号 – doctorlove

+1

你能解释一下你是如何确定你想输出的吗?[[''a'],['b','c','d']] '?为什么'b'与'c'和'd'在同一个列表中,当它具有不同的概率? – Kevin

+0

@doctorlove是的,当然。已添加冒号并删除第一长度。 –

回答

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

我有一个递归解决方案。

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

一个包含两个列表从两侧较低的树枝树叶列表。

编辑:

这个代码是根据在原来的问题给出的格式:)0.125

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

如果输入格式被改变,那么这将不起作用。

+0

感谢您的答案,但不幸的是,解决方案不能递归,因为我无法控制树的大小(符号数可能是1000)。 –

+0

将其转换为迭代解决方案不应太困难。正如@Kevin在评论中提到的,这似乎是对实际树的更明智的表示。您可以随时以任何方式解开第一个和第二个元素。 – drexiya

+0

如果您有一些大型数据集,我会对这两种解决方案的相对性能感兴趣。 – drexiya

0

看起来像是一个通用算法,您需要一个函数(1)计算下面的树的总权重,然后(2)实现树的旋转来旋转树,直到达到平衡。即在某些方面,这仅仅是标准树平衡算法的变体,除了例如对于AVL树来说,您正在平衡深度,并且在这里您正在权衡数据本身。

+0

可否请您详细说明您的数据的重量是什么意思? –

+0

不知道我完全理解算法,但它听起来像每个项目有一个概率,应该加起来1.0(或频率,在这种情况下总数会更高)。在任何情况下,理想情况下,您最终想要一棵右边的树在中间,这样左边大约等于右边(将根添加到一边或另一边)。这就是我所说的平衡。即树根可能看起来像'b',左边是'a',右边是'c'/'d'。按顺序遍历每一边进行提取。因为(a-(b + cd))<((b + cd)-a) –

+0

事实证明,你只需使用广度优先搜索去掉叶子。 –