0

My input is

[['apple',{'john':3,'anna':4,'kitty':6}],['pear',{'john':4,'anna':3,'kitty':3}]]

Expected output:

{
    'key':['apple','pear'],
    'value':[
        {
            'name':'john',
            'data':[3,4]
        },
        {
            'name':'anna',
            'data':[4,3]
        },
        {
            'name':'kitty',
            'data':[6,3]
        }
    ]
}

The key is a list which conclude the first part of each item, such as 'apple' 'pear', and the value is another list.

How should I do it?

1
  • 7
    Want to share your attempts with us? Commented Nov 4, 2015 at 6:19

4 Answers 4

2

You can achieve this with the help of collections.defaultdict:

from collections import defaultdict
value, key = defaultdict(list), []

for x in l:
    key.append(x[0])
    for k, v in x[1].items():
        value[k].append(v)

To get the result:

In [15]: {'key': key, 'value': [{'name': k, 'data': v} for k, v in value.items()]}
Out[15]: 
{'key': ['apple', 'pear'],
 'value': [
  {'data': [4, 3], 'name': 'anna'},
  {'data': [6, 3], 'name': 'kitty'},
  {'data': [3, 4], 'name': 'john'}]}

For a more efficient (?) version, subclass defaultdict to customize the default __missing__ hook to call the default_factory with missing key as a parameter (I copied this text and the implementation from the other answer of mine). Then you'll be able to do this in a single pass:

from collections import defaultdict

class mydefaultdict(defaultdict):
    def __missing__(self, key):
        self[key] = value = self.default_factory(key)
        return value

# pass 'name' to the dictionary
value = mydefaultdict(lambda name: {'name': name, 'data': []})
key = []

for x in l:
    key.append(x[0])
    for k, v in x[1].items():
        value[k]['data'].append(v)

The result is then

In [24]: {'key': key, 'value': value.values()}
Out[24]: 
{'key': ['apple', 'pear'],
 'value': [
  {'data': [4, 3], 'name': 'anna'},
  {'data': [6, 3], 'name': 'kitty'},
  {'data': [3, 4], 'name': 'john'}]}

In Python 3, you'll have to call list(value.values()) instead of just value.values() to get a list object.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use following snippet:

input = [['apple',{'john':3,'anna':4,'kitty':6}],['pear',{'john':4,'anna':3,'kitty':3}]]

tmp = {}
output = {'key': [], 'value': []}

for item in input:
    output['key'].append(item[0])
    for name in item[1]:
        try:
            tmp[name].append(item[1][name])
        except KeyError:
            tmp[name] = [item[1][name]]

output['value'] = [{'name': name, 'data': data} for name, data in tmp.items()]

Comments

1

This function can help you

def map_data(data):
    _tmp = {}
    _keys = []
    for _d in data:
        _keys.append(_d[0])
        for _k in _d[1].keys():
            _v  = _tmp.get(_k)
            if not _v:
                _v = {"name": _k, "data": []}

            _v["data"].append(_d[1][_k])
            _tmp[_k] = _v

    return {"key": _keys, "value": [_v for _v in _tmp.values()]}

Comments

1

Here is my solution:

import json                                                                                         

my_list = [['apple',{'john':3,'anna':4,'kitty':6}],['pear',{'john':4,'anna':3,'kitty':3}]]

name_list = [item[1] for item in my_list]  # [{'john': 3, 'kitty': 6, 'anna': 4}, {'john': 4, 'kitty
names = name_list[0].keys()  # ['john', 'kitty', 'anna']                       
name_values = [[item[key] for item in name_list] for key in names]  # [[3, 4], [6, 3], [4, 3]]
result = {                                                                     
    'key': [item[0] for item in my_list],                                      
    'value': [                                                                 
        {'name': name, 'value': value}                                         
        for (name, value) in zip(names, name_values)                           
    ]                                                                          
}                                                                              

print(json.dumps(result, indent=4))

And the output:

{
    "value": [
        {
            "name": "john", 
            "value": [
                3, 
                4
            ]
        }, 
        {
            "name": "kitty", 
            "value": [
                6, 
                3
            ]
        }, 
        {
            "name": "anna", 
            "value": [
                4, 
                3
            ]
        }
    ], 
    "key": [
        "apple", 
        "pear"
    ]
}

EDIT:

emmm, just found a better way to merge the dict value.

If the name_dict look like this one:

>>> name_dict
[{'john': [3], 'kitty': [6], 'anna': [4]}, {'john': [4], 'kitty': [3], 'anna': [3]}]

the task would be easy. What's the difference? The value is a list.

Now, we can use collections.Counter to merge two dicts!

>>> Counter(name_dict[0]) + Counter(name_dict[1])
Counter({'kitty': [6, 3], 'anna': [4, 3], 'john': [3, 4]})

so here is the new solution, we convert the value to a list first:(skip the 'key', only show the 'value'):

  from collections import Counter 

  my_list = [['apple',{'john':3,'anna':4,'kitty':6}],['pear',{'john':4,'anna':3,'kitty':3}]]
  name_list = [item[1] for item in my_list]    

  for item in name_list:                                                          
      for key, value in item.items():                                             
          item[key] = [value]                                                     

  name_values = dict(Counter(name_list[0]) + Counter(name_list[1]))  # {'john': [3, 4], 'kitty': [6, 3], 'anna': [4, 3]}             

  print([{'name': name, 'value': value} for (name, value) in name_values.items()])

  # output
  [{'name': 'john', 'value': [3, 4]}, {'name': 'kitty', 'value': [6, 3]}, {'name': 'anna', 'value': [4, 3]}]

3 Comments

that's a pretty way,what if the name_list is a huge object?
@user1594252 ah, it's name_list = [item[1] for item in my_list], just in the first version of this answer.
@user1594252 Updated the answer, hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.