Reputation: 41
I want to take a list, e.g. [0, 1, 0, 1, 2, 2, 3]
, and make a list of lists of (index + 1)
for each of the unique elements. For the above, for example, it would be [[1, 3], [2, 4], [5, 6], [7]]
.
Right now my solution is the ultimate in clunkiness:
list_1 = [0, 1, 0, 1, 2, 2, 3]
maximum = max(list_1)
master = []
for i in range(maximum + 1):
temp_list = []
for j,k in enumerate(list_1):
if k == i:
temp_list.append(j + 1)
master.append(temp_list)
print master
Any thoughts on a more pythonic way to do this would be much appreciated!
Upvotes: 1
Views: 294
Reputation: 122032
I would do this in two steps:
Build a map {value: [list, of, indices], ...}
:
index_map = {}
for index, value in enumerate(list_1):
index_map.setdefault(value, []).append(index+1)
Extract the value lists from the dictionary into your master
list:
master = [index_map.get(index, []) for index in range(max(index_map)+1)]
For your example, this would give:
>>> index_map
{0: [1, 3], 1: [2, 4], 2: [5, 6], 3: [7]}
>>> master
[[1, 3], [2, 4], [5, 6], [7]]
This implementation iterates over the whole list only once (O(n)
, where n
is len(list_1)
) whereas the others so far iterate over the whole list once for each unique element (O(n*m)
, where m
is len(set(list_1))
). By taking max(d)
rather than max(list_1)
you only need to iterate over the length of the unique items, which is also more efficient.
The implementation can be slightly simpler if you make d = collections.defaultdict(list)
.
Upvotes: 3
Reputation: 19627
master = [[i+1 for i in range(len(list_1)) if list_1[i]==j] for j in range(max(list_1)+1)]
It is just the same that your current code, but it uses list comprehension which is often a quite good pythonic way to solve this kind of problem.
Upvotes: 0
Reputation: 10218
list_1 = [0, 1, 0, 1, 2, 2, 3]
master = []
for i in range(max(list_1)+1):
master.append([j+1 for j,k in enumerate(list_1) if k==i])
Upvotes: 0