Python:字典列表之间的减法

发布于 2024-10-24 07:48:08 字数 1806 浏览 2 评论 0原文

我有 2 个包含字典的列表,如下:

listone = [{'unit1': {'test1': 10}}, 
           {'unit1': {'test2': 45'}, 
           {'unit2': {'test1': 78'}, 
           {'unit2': {'test2': 2'}}]

listtwo = [{'unit1': {'test1': 56}}, 
           {'unit1': {'test2': 34'}, 
           {'unit2': {'test1': 23'}, 
           {'unit2': {'test2': 5'}}]

我也有所有单位名称和单位名称。单独列表中的测试名称:

units = ['unit1', 'unit2']
testnames = ['test1,'test2']

如何找到每个测试值的增量,即 (test2 - test1) 的 val,以便我最终可以将数据排列为如下:

unit1, test1, delta
unit1, test2, delta
unit2, test1, delta
unit2, test2, delta

到目前为止,我有这些:

def delta(array1, array2):
        temp = []
        temp2 = []
        tmp = []
        tmp2 = []
        delta = []
        for unit in units:
            for mkey in array1:
                for skey in mkey:
                    if skey == unit:
                        temp.append(mkey[skey])
                        floater(temp) #floats all the values
                        for i in testnames:
                            for u in temp:
                                tmp.append(u[i])
                                tmp = filter(None, tmp2)

            for mkey in array2:
                for skey in mkey:
                    if skey == unit:
                        temp.append(mkey[skey])
                        floater(temp2)
                        for i in testnames:
                            for u in temp2:
                                tmp2.append(u[i])
                                tmp2 = filter(None, tmp2)

        delta = [tmp2 - tmp for tmp2, tmp in zip(tmp2, tmp)] 
        print delta

delta(listone,listtwo)

不幸的是,代码给出了Keyerror。 :( 请帮忙。谢谢。

I have 2 list containing dictionaries as follows:

listone = [{'unit1': {'test1': 10}}, 
           {'unit1': {'test2': 45'}, 
           {'unit2': {'test1': 78'}, 
           {'unit2': {'test2': 2'}}]

listtwo = [{'unit1': {'test1': 56}}, 
           {'unit1': {'test2': 34'}, 
           {'unit2': {'test1': 23'}, 
           {'unit2': {'test2': 5'}}]

I also do have all the unit names & test-names in separate lists:

units = ['unit1', 'unit2']
testnames = ['test1,'test2']

How could I find the delta for each test value, i.e. val of (test2 - test1), so that I could finally arrange the data as follows:

unit1, test1, delta
unit1, test2, delta
unit2, test1, delta
unit2, test2, delta

So far, I have these:

def delta(array1, array2):
        temp = []
        temp2 = []
        tmp = []
        tmp2 = []
        delta = []
        for unit in units:
            for mkey in array1:
                for skey in mkey:
                    if skey == unit:
                        temp.append(mkey[skey])
                        floater(temp) #floats all the values
                        for i in testnames:
                            for u in temp:
                                tmp.append(u[i])
                                tmp = filter(None, tmp2)

            for mkey in array2:
                for skey in mkey:
                    if skey == unit:
                        temp.append(mkey[skey])
                        floater(temp2)
                        for i in testnames:
                            for u in temp2:
                                tmp2.append(u[i])
                                tmp2 = filter(None, tmp2)

        delta = [tmp2 - tmp for tmp2, tmp in zip(tmp2, tmp)] 
        print delta

delta(listone,listtwo)

Unfortunately, the code gives Keyerror. :(
Help, please. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

卷耳 2024-10-31 07:48:08

也许将您的数据转换为不同的、更方便的数据结构。
例如,使用像这样的单个字典而不是 listone 会更容易:

{('unit1', 'test1'): 10,
 ('unit2', 'test1'): 78,
 ('unit2', 'test2'): 2,
 ('unit1', 'test2'): 45}

所以给定,

import itertools
units = ['unit1', 'unit2']
testnames = ['test1','test2']
listone = [{'unit1': {'test1': 10}}, 
           {'unit1': {'test2': 45}}, 
           {'unit2': {'test1': 78}}, 
           {'unit2': {'test2': 2}}]

listtwo = [{'unit1': {'test1': 56}}, 
           {'unit1': {'test2': 34}}, 
           {'unit2': {'test1': 23}}, 
           {'unit2': {'test2': 5}}]

这里我们转换 listonelisttwo到字典列表:

dicts=[{},{}]
for i,alist in enumerate([listone,listtwo]):
    for item in alist:
        for unit,testdict in item.iteritems():
            for testname,value in testdict.iteritems():
                dicts[i][unit,testname]=value

现在找到deltas很容易:

for unit,testname in itertools.product(units,testnames):
    delta=dicts[1][unit,testname]-dicts[0][unit,testname]
    print('{u}, {t}, {d}'.format(u=unit,t=testname,d=delta))

产量

unit1, test1, 46
unit1, test2, -11
unit2, test1, -55
unit2, test2, 3

Perhaps convert your data to a different, more convenient data structure.
For example, instead of listone, it would be easier to work with a single dict like this:

{('unit1', 'test1'): 10,
 ('unit2', 'test1'): 78,
 ('unit2', 'test2'): 2,
 ('unit1', 'test2'): 45}

So given,

import itertools
units = ['unit1', 'unit2']
testnames = ['test1','test2']
listone = [{'unit1': {'test1': 10}}, 
           {'unit1': {'test2': 45}}, 
           {'unit2': {'test1': 78}}, 
           {'unit2': {'test2': 2}}]

listtwo = [{'unit1': {'test1': 56}}, 
           {'unit1': {'test2': 34}}, 
           {'unit2': {'test1': 23}}, 
           {'unit2': {'test2': 5}}]

Here we convert listone and listtwo to a list of dicts:

dicts=[{},{}]
for i,alist in enumerate([listone,listtwo]):
    for item in alist:
        for unit,testdict in item.iteritems():
            for testname,value in testdict.iteritems():
                dicts[i][unit,testname]=value

Now finding the deltas is easy:

for unit,testname in itertools.product(units,testnames):
    delta=dicts[1][unit,testname]-dicts[0][unit,testname]
    print('{u}, {t}, {d}'.format(u=unit,t=testname,d=delta))

yields

unit1, test1, 46
unit1, test2, -11
unit2, test1, -55
unit2, test2, 3
关于从前 2024-10-31 07:48:08

类似但更封装:

from collections import defaultdict

listone = [
    {'unit1': {'test1': 10}},
    {'unit1': {'test2': 45}}, 
    {'unit2': {'test1': 78}}, 
    {'unit2': {'test2': 2}}
]

listtwo = [
    {'unit1': {'test1': 56}},
    {'unit1': {'test2': 34}}, 
    {'unit2': {'test1': 23}}, 
    {'unit2': {'test2': 5}}
]

def dictify(lst):
    res = defaultdict(lambda: defaultdict(int))
    for entry in lst:
        for unit,testentry in entry.iteritems():
            for test,val in testentry.iteritems():
                res[unit][test] = val
    return res
    # returns dict['unitX']['testY'] = val

def genDeltas(dictA, dictB):
    units = dictA.keys()
    units.sort()
    tests = dictA[units[0]].keys()
    tests.sort()
    for unit in units:
        _A = dictA[unit]
        _B = dictB[unit]
        for test in tests:
            yield unit,test,(_B[test]-_A[test])

for unit,test,delta in genDeltas(dictify(listone),dictify(listtwo)):
    print "{0}, {1}, {2}".format(unit,test,delta)

编辑:查找字段平均值:

class Avg(object):
    def __init__(self, total=0.0, num=0):
        super(Avg,self).__init__()
        self.total = total
        self.num   = num

    def add(self, value):
        self.total += value
        self.num   += 1

    def value(self):
        return self.total / self.num

def avgBy(data, field=0):
    res = defaultdict(Avg)
    for unit,testdict in data.iteritems():
        for test,val in testdict.iteritems():
            res[(unit,test)[field]].add(val)
    return {item:avg.value() for item,avg in res.iteritems()}

dictone = dictify(listone)
avg_by_unit = avgBy(dictone, 0)
print(avg_by_unit)
avg_by_test = avgBy(dictone, 1)
print(avg_by_test)

Similar but a bit more encapsulated:

from collections import defaultdict

listone = [
    {'unit1': {'test1': 10}},
    {'unit1': {'test2': 45}}, 
    {'unit2': {'test1': 78}}, 
    {'unit2': {'test2': 2}}
]

listtwo = [
    {'unit1': {'test1': 56}},
    {'unit1': {'test2': 34}}, 
    {'unit2': {'test1': 23}}, 
    {'unit2': {'test2': 5}}
]

def dictify(lst):
    res = defaultdict(lambda: defaultdict(int))
    for entry in lst:
        for unit,testentry in entry.iteritems():
            for test,val in testentry.iteritems():
                res[unit][test] = val
    return res
    # returns dict['unitX']['testY'] = val

def genDeltas(dictA, dictB):
    units = dictA.keys()
    units.sort()
    tests = dictA[units[0]].keys()
    tests.sort()
    for unit in units:
        _A = dictA[unit]
        _B = dictB[unit]
        for test in tests:
            yield unit,test,(_B[test]-_A[test])

for unit,test,delta in genDeltas(dictify(listone),dictify(listtwo)):
    print "{0}, {1}, {2}".format(unit,test,delta)

Edit: to find field-averages:

class Avg(object):
    def __init__(self, total=0.0, num=0):
        super(Avg,self).__init__()
        self.total = total
        self.num   = num

    def add(self, value):
        self.total += value
        self.num   += 1

    def value(self):
        return self.total / self.num

def avgBy(data, field=0):
    res = defaultdict(Avg)
    for unit,testdict in data.iteritems():
        for test,val in testdict.iteritems():
            res[(unit,test)[field]].add(val)
    return {item:avg.value() for item,avg in res.iteritems()}

dictone = dictify(listone)
avg_by_unit = avgBy(dictone, 0)
print(avg_by_unit)
avg_by_test = avgBy(dictone, 1)
print(avg_by_test)
删除→记忆 2024-10-31 07:48:08

我认为使用词典的词典更容易完成。在这里,我分步骤定义它们,因为我假设您正在从某些测试过程中收集结果,但您也可以在一行中完成。

listOne = {}
listOne['unit1'] = {}
listOne['unit2'] = {}
listOne['unit1']['test1']=10
listOne['unit1']['test2']=45
listOne['unit2']['test1'] = 78
listOne['unit2']['test2'] = 2

listTwo = {}
listTwo['unit1'] = {}
listTwo['unit2'] = {}
listTwo['unit1']['test1']=56
listTwo['unit1']['test2']=34
listTwo['unit2']['test1'] = 23
listTwo['unit2']['test2'] = 5

units = ['unit1', 'unit2']
testnames = ['test1','test2']

deltas = {}

# collect the deltas
for unit in units :
    deltas[unit] = {}
    for test in testnames :
        deltas[unit][test] = listTwo[unit][test] -listOne[unit][test]

# print put the results
for unit in units :
    for test in testnames :
        print unit, ', ', test, ', ', deltas[unit][test]

这产生

unit1 ,  test1 ,  46
unit1 ,  test2 ,  -11
unit2 ,  test1 ,  -55
unit2 ,  test2 ,  3

I think it is easier done with dictionaries of dictionaries. Here, I define them in steps, since I assume you're gathering the results from some testing process, but you can also do it in one line.

listOne = {}
listOne['unit1'] = {}
listOne['unit2'] = {}
listOne['unit1']['test1']=10
listOne['unit1']['test2']=45
listOne['unit2']['test1'] = 78
listOne['unit2']['test2'] = 2

listTwo = {}
listTwo['unit1'] = {}
listTwo['unit2'] = {}
listTwo['unit1']['test1']=56
listTwo['unit1']['test2']=34
listTwo['unit2']['test1'] = 23
listTwo['unit2']['test2'] = 5

units = ['unit1', 'unit2']
testnames = ['test1','test2']

deltas = {}

# collect the deltas
for unit in units :
    deltas[unit] = {}
    for test in testnames :
        deltas[unit][test] = listTwo[unit][test] -listOne[unit][test]

# print put the results
for unit in units :
    for test in testnames :
        print unit, ', ', test, ', ', deltas[unit][test]

This yields

unit1 ,  test1 ,  46
unit1 ,  test2 ,  -11
unit2 ,  test1 ,  -55
unit2 ,  test2 ,  3
土豪 2024-10-31 07:48:08

这将解决您当前的问题:

listone = [{'unit1': {'test1': 10}}, 
    {'unit1': {'test2': 45}}, 
    {'unit2': {'test1': 78}}, 
       {'unit2': {'test2': 2}}]

listtwo = [{'unit1': {'test1': 56}}, 
    {'unit1': {'test2': 34}}, 
    {'unit2': {'test1': 23}}, 
           {'unit2': {'test2': 5}}]

units = ['unit1', 'unit2']
testnames = ['test1', 'test2']


# Iterate over all units
for unit in units:
    # Iterate over all tests
    for test in testnames:
        # Find the rows corresponding to our current unit/test
        list1Row = [i for i,d in enumerate(listone) if d.keys()[0] == unit and d.values()[0].keys()[0] == test]
        list2Row = [i for i,d in enumerate(listtwo) if d.keys()[0] == unit and d.values()[0].keys()[0] == test]

        # Check to make sure there was exactly one match.
        # This is another weakness of your data structure.
        if (len(list1Row) == 1) and (len(list2Row) == 1):
            list1Row = list1Row[0]
            list2Row = list2Row[0]
            delta = listtwo[list2Row].values()[0].values()[0] - listone[list1Row].values()[0].values()[0]
            print unit, test, delta

但是,正如前面的海报所建议的那样,您确实应该考虑不同的数据结构。我建议使用类似带有(单元,测试)键和列表值的单个字典。

This will solve your current problem:

listone = [{'unit1': {'test1': 10}}, 
    {'unit1': {'test2': 45}}, 
    {'unit2': {'test1': 78}}, 
       {'unit2': {'test2': 2}}]

listtwo = [{'unit1': {'test1': 56}}, 
    {'unit1': {'test2': 34}}, 
    {'unit2': {'test1': 23}}, 
           {'unit2': {'test2': 5}}]

units = ['unit1', 'unit2']
testnames = ['test1', 'test2']


# Iterate over all units
for unit in units:
    # Iterate over all tests
    for test in testnames:
        # Find the rows corresponding to our current unit/test
        list1Row = [i for i,d in enumerate(listone) if d.keys()[0] == unit and d.values()[0].keys()[0] == test]
        list2Row = [i for i,d in enumerate(listtwo) if d.keys()[0] == unit and d.values()[0].keys()[0] == test]

        # Check to make sure there was exactly one match.
        # This is another weakness of your data structure.
        if (len(list1Row) == 1) and (len(list2Row) == 1):
            list1Row = list1Row[0]
            list2Row = list2Row[0]
            delta = listtwo[list2Row].values()[0].values()[0] - listone[list1Row].values()[0].values()[0]
            print unit, test, delta

However, as the previous poster recommended, you should really consider a different data structure. I would suggest something like a single dictionary with a (unit, test) key and a list value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文