用于创建列表dict的dict的Python习语

时间:2014-03-12 08:34:57

标签: python

鉴于此数据:

foo kk type1 1 2 3
bar kk type2 3 5 1

我想创建一个列表字典的字典。

在Perl中,它被称为数组哈希的哈希。 它可以通过以下行实现(在此处可执行https://eval.in/118535

push @{$hohoa{$name}{$type}},($v1,$v2,$v3);

Perl中$ hohoa的输出:

$VAR1 = {
          'bar' => {
                     'type2' => [
                                  '3',
                                  '5',
                                  '1'
                                ]
                   },
          'foo' => {
                     'type1' => [
                                  '1',
                                  '2',
                                  '3'
                                ]
                   }
        };

在Python中使用它的方法是什么?

更新:为什么以下for loop变体并未存储所有值?

#!/usr/bin/env python

import sys
import pprint
from collections import defaultdict

outerdict = defaultdict(dict)
with open('data.txt') as infh:
    for line in infh:
        name, _, type_, values = line.split(None, 3)

        valist = values.split();
        for i in range(len(valist)):
            thval = valist[i];
            outerdict[name][type] = thval

pp = pprint.PrettyPrinter(indent=4)
pp.pprint(outerdict)

打印出来:

defaultdict(<type 'dict'>, {'foo': {<type 'type'>: '3'}, 'bar': {<type 'type'>: '1'}})

更新2:输出似乎有问题 当数据看起来像这样:

foo kk type1 1.2 2.10 3.3
bar kk type2 3.2 5.2 1.0

4 个答案:

答案 0 :(得分:6)

这取决于你想要达到的目标;应该在内部字典中添加多少个键?

最简单的方法是为内部字典创建新的字典文字:

outerdict = {}
outerdict[name] = {type_: [v1, v2, v3]}

或者您可以根据需要使用dict.setdefault()来实现内部字典:

outerdict.setdefault(name, {})[type_] = [v1, v2, v3]

或者您可以使用collections.defaultdict()让它为您处理新值:

from collections import defaultdict

outerdict = defaultdict(dict)
outerdict[name][type_] = [v1, v2, v3]

逐行解析文件时,我会使用后者,尽管有点简化:

from collections import defaultdict

outerdict = defaultdict(dict)
with open(filename) as infh:
    for line in infh:
        name, _, type_, *values = line.split()
        outerdict[name][type_] = [int(i) for i in values]

这使用Python 3语法将前3行的剩余空格分隔值捕获到values

Python 2版本将是:

with open(filename) as infh:
    for line in infh:
        name, _, type_, values = line.split(None, 3)
        outerdict[name][type_] = map(int, values.split())

我将空格分割限制为仅3个分割(给出4个值),然后分别分割values字符串。

要让最里面的列表为重复的(name, type_)组合键累积所有值,您需要使用稍微复杂的defaultdict设置;一个产生内部 defaultdict()设置以产生list值的产品:

outerdict = defaultdict(lambda: defaultdict(list))
with open(filename) as infh:
    for line in infh:
        name, _, type_, values = line.split(None, 3)
        outerdict[name][type_].extend(map(int, values.split()))

对于您实际发布的文件,我完全使用不同的方法

import csv
from itertools import islice

outerdict = defaultdict(lambda: defaultdict(list))

with open('ImmgenCons_all_celltypes_MicroarrayExp.csv', 'rb') as infh:
    reader = csv.reader(infh, skipinitialspace=True)
    # first row contains metadata we need
    celltypes = next(reader, [])[3:]

    # next two rows can be skipped
    next(islice(infh, 2, 2), None)

    for row in reader:
        name = row[1]
        for celltype, value in zip(celltypes, row[3:]):
            outerdict[name][celltype].append(float(value))

答案 1 :(得分:1)

def make_strukture(lst_of_str):
    result = {}
    for i in my_strs:
        data = i.split()
        if data[0] in result.keys(): continue #Only one first key for foo, bar
        result[data[0]] = {} #Create first key foo, bar-level
        result[data[0]][data[2]] = list(data[3:]) #Skip kk and create second key with list
    return result

#Below more comples data structure:
my_strs = ["foo kk type1 1 2 3", "foo kk type2 1 2 3", "bar kk type2 3 5 1"]
print make_strukture(my_strs)

打印结果:

{'foo':
    {'type1': ['1', '2', '3']},
 'bar': 
    {'type2': ['3', '5', '1']}
}

答案 2 :(得分:1)

另一个很好的方法是执行以下操作:

from collections import defaultdict

d = defaultdict(lambda: defaultdict(list))

# eg.
d["x"]["y"].append(100)

通过这种方式,您将创建一个默认值为list的许多字典的字典。

答案 3 :(得分:0)

您可以使用defaultdict dictreduce来使用普通dict.setdefault,而不是使用text_data = """foo kk type1 1 2 3 bar kk type2 3 5 1""" data = [line.split() for line in text_data.splitlines()] # [['foo', 'kk', 'type1', '1', '2', '3'], ['bar', 'kk', 'type2', '3', '5', '1']] var1 = {} for row in data: # row[:2] everything before leaf, [2] is the leaf, row[3:] remainder of 'values' reduce(lambda a,b: a.setdefault(b, {}), row[:2], var1)[2] = row[3:] # {'foo': {'kk': {2: ['1', '2', '3']}}, 'bar': {'kk': {2: ['3', '5', '1']}}} 。这是一个可以包含在函数中的示例:

def nested_dict(sequences, n, converter=lambda L: L):
    ret = {}
    for seq in sequences:
        reduce(lambda a,b: a.setdefault(b, {}), seq[:n-1], ret)[n] = map(converter, seq[n:])
    return ret

nested_dict(data, 2)
#{'foo': {2: ['type1', '1', '2', '3']}, 'bar': {2: ['type2', '3', '5', '1']}}
nested_dict(data, 3)
# {'foo': {'kk': {3: ['1', '2', '3']}}, 'bar': {'kk': {3: ['3', '5', '1']}}}
nested_dict(data, 3, int)
# {'foo': {'kk': {3: [1, 2, 3]}}, 'bar': {'kk': {3: [3, 5, 1]}}}
# ...

然后,将其包装到具有值的可选转换器的函数中,例如:

{{1}}