Reputation: 4510
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
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
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