Reputation: 59
I have a dictionary dict = {1:['cup','pen'],2:['one','two'],3:['five']}
in which i have to iterate through the first elements of all the keys
at first and then the second element.
I have written in below way, but the output in which it,iterates through list index 0
first and then index 1
.
Any one help me out to modify the code, so that it can iterate all the list's first element's at first and the second element
dict = {1:['cup','pen'],2:['one','two'],3:['five']}
for v in dict.values():
for i in range (len(v)):
print v[i]
Output of above code:
cup
pen
one
two
five
but want it in this below way :
cup
one
five
pen
two
Upvotes: 3
Views: 306
Reputation:
You can try this without any external library:
dict = {1:['cup','pen'],2:['one','two'],3:['five']}
track={}
for i,ja in dict.items():
for k,n in enumerate(ja):
if k not in track:
track[k]=[n]
else:
track[k].append(n)
for k in track.values():
for m in k:
print(m)
output:
cup
one
five
pen
two
Upvotes: 1
Reputation: 402333
Using the zipped-transpose idiom, zip upto the longest list with itertools.zip_longest
. Then iterate over each item in the sub-lists, filtering out None
values.
from itertools import zip_longest
for i in zip_longest(*data.values()):
for j in filter(None, i):
print(j)
cup
one
five
pen
two
Here, data
is your input dictionary. Don't use dict
to name variables, it shadows the builtin class with the same name.
Note that this order is not guaranteed on python versions below python-3.6, since dictionaries are not ordered in these older versions of python.
Final note, for python-2.x, the appropriate function to be used is itertools.izip_longest
.
The output of zip_longest
looks like this:
print(list(zip_longest(*data.values())))
[('cup', 'one', 'five'), ('pen', 'two', None)]
These None
values are inserted in place of missing values due to the "zip longest' behaviour of the function. These None
s are removed with filter
.
You can use this to get creative using itertools.chain
and a print
statement, accomplishing this in one line:
from itertools import chain
print(*filter(None, chain.from_iterable(zip_longest(*data.values()))), sep='\n')
cup
one
five
pen
two
Re-written a little more clearly:
print(
*filter( # `filter` out None (iterable unpacking)
None,
chain.from_iterable( # flatten an iterable of iterables
zip_longest(*data.values()) # zip-longest transpose
)
),
sep='\n' # separate unpacked arguments with newline
)
One more option, for homework submission without zip_longest
. This just cycles over the keys, popping one element at a time from each list.
while any(bool(v) for v in data.values()):
for k in data:
try:
print(data[k].pop(0))
except IndexError:
pass
cup
one
five
pen
two
This empties data
of its contents, so you may want to make a copy of your data beforehand.
Upvotes: 3
Reputation: 26315
You could try converting each list in your dictionary to collections.deqeue()
objects, then popping off the first item in each queue until all queues are empty:
from collections import deque
d = {1:['cup','pen'],2:['one','two'],3:['five']}
# convert to deques
lsts = [deque(x) for x in d.values()]
# while lsts still has queues to pop
while lsts:
# go over all the queues again
for lst in lsts:
# if it is not empty, pop it off and print it.
if len(lst) > 0:
print(lst.popleft())
# only keep queues that are not empty
lsts = [x for x in lsts if x]
Which Outputs:
cup
one
five
pen
two
Having shown this possible approach, it does require more work to produce what you want, whereas @cᴏʟᴅsᴘᴇᴇᴅ's answer addresses how to do this very easily.
Also note that you don't need to use collections.deque()
here, you can simply pop from lists instead with pop()
. I used it for convenience and the O(1)
popleft()
function.
The only efficiency issue you can run into here is that pop(0)
is O(n)
for lists. One way around this is reversing the lists beforehand, and calling pop()
instead, which results in O(1)
behavior.
Upvotes: 3