NullException
NullException

Reputation: 4510

python list of tuples to list of dictionary of nested lists

I am trying to convert list of tuples (example z below) to z1. First 2 items in z can be same and so becomes common field in result's dictionary. Please below. My attempt is shown as well but it fails to group common element? Any help?

FROM:

z= [(53, 'example 2', 2, 'instagram', 'nyc'),
    (53, 'example 2', 5, 'instagram', 'detroit'),
    (53, 'example 2', 7, 'twitter', 'harlem'),
    (50, 'example 5', 8, 'twitter', 'harlem'),
    (27, 'example 6', None, None, None), 
   ]

TO:

z1=[
 {'id':        53,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 2, 'platform': 'instagram', 'tagname': 'nyc' },
                 { 'tag_id': 5, 'platform': 'instagram', 'tagname': 'detroit' },
                 { 'tag_id': 7, 'platform': 'twitter',   'tagname': 'harlem' },
               ]
 },
 {'id':        50,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 8, 'platform': 'twitter', 'tagname': 'harlem' },
               ]
 },
 {'id':        27,
  'name':      'example 6',
  'hashtags':  [ { 'tag_id': None, 'platform': None, 'tagname': None },
               ]
 },
]

My Attempt:

ld = []
for a, b, c, d, e in z:
    ld.append({ 'id':       a,
                'name':     b,
                'tag_id':   c,
                'hashtags': [{'platform': d, 'hashtag':  e}, ]
             })

print ld

Output:

[
 {'id':        53,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 2, 'platform': 'instagram', 'tagname': 'nyc' }]
 },
 {'id':        53,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 5, 'platform': 'instagram', 'tagname': 'detroit' }]
 },
 {'id':        53,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 7, 'platform': 'twitter',   'tagname': 'harlem' },]
 },
 {'id':        50,
  'name':      'example 2',
  'hashtags':  [ { 'tag_id': 8, 'platform': 'twitter', 'tagname': 'harlem' },
               ]
 },
 {'id':        27,
  'name':      'example 6',
  'hashtags':  [ { 'tag_id': None, 'platform': None, 'tagname': None },
               ]
 },
]

Upvotes: 0

Views: 174

Answers (2)

Geoff
Geoff

Reputation: 2491

The problem is that you aren't looking to see if you've already added a dict with the given id to ld ("Have I already added the element with id 53 to the list?"). You need to check to see if you've already added it.

The first thing that comes to mind is storing previous ids in a dict mapping the to the index. This doesn't increase the runtime complexity.

ld = []
encountered_id_index = {}
for a, b, c, d, e in z:
    if a in encountered_id_index:
        index = encountered_id_index[a]
        ld_dict = ld[index]
        ld_dict['hashtags'].append({'platform': d, 'hashtag': e, 'tag_id': c})
    else:
        ld.append({ 'id': a,
                    'name': b,
                    'hashtags': [{'platform': d, 'hashtag': e, 'tag_id': c}]
        })
        index = len(ld) - 1
        encountered_id_index[a] = index

This is untested, but I think that should get the job done.

Unrelated, but I'd recommend changing the variable names in the for loop to something more meaningful. "id" instead of "a", "name" instead of "b", etc. I promise you that if you learn to properly name your variables now, you'll have fewer headaches in the future. It dramatically increases readability of your code.

Upvotes: 3

Hugh Bothwell
Hugh Bothwell

Reputation: 56654

from collections import defaultdict, namedtuple

HashTag = namedtuple('HashTag', ['tag_id', 'platform', 'tag_name'])

class Entries:
    def __init__(self):
        self.entries = defaultdict(list)

    def add_entry(self, id, name, tag_id, platform, tag_name):
        key = (id, name)
        value = HashTag(tag_id, platform, tag_name)
        self.entries[key].append(value)

z1 = Entries()
for entry in z:
    z1.add_entry(*entry)

... the only thing I don't like about this is that you need to know both the id and name to look up an entry. If I were using this seriously, I would modify it to index entries only on id, then have a second dict linking name to id, then implement __ getitem __ such that it will do a lookup on either id or name.

Upvotes: 1

Related Questions