3

In my Django app I have 2 querysets of the same object. I know I can merge 2 querysets using itertools and chain like so:

from itertools import chain
list(chain(first_queryset, second_queryset))

But this outputs a new queryset where the entire first one is followed by the entire second one like so:

[<first_queryset_1st_instance>, <first_queryset_2nd_instance>,       <first_queryset_3rd_instance>, <second_queryset_1st_instance>, <second_queryset_2nd_instance>, <second_queryset_3rd_instance>]

However, I really need an output that is alternating between each queryset instead of just appending the entire second queryset at the end of the first one like so:

[<first_queryset_1st_instance>, <second_queryset_1st_instance>,<first_queryset_2nd_instance>, <second_queryset_2nd_instance>, <first_queryset_3rd_instance>, <second_queryset_3rd_instance>]

What's the best way I can do this in python/django?

Alasdair
  • 298,606
  • 55
  • 578
  • 516
EazyC
  • 809
  • 1
  • 10
  • 30

1 Answers1

3

You can get the result you need using zip_longest, chain and filter together.

Lets call the querysets p and q. Then you would do:

# Python 3.x
from itertools import chain, zip_longest
combined = list(filter(lambda x: x is not None, chain(*zip_longest(p, q))))

# Python 2.7
from itertools import chain, ifilter, izip_longest
combined = list(ifilter(lambda x: x is not None, chain(*izip_longest(p, q))))

Let's explain how it works. First, zip_longest (izip_longest in Python 2) zips the querysets together. You want zip_longest instead of zip, so that the output continues after the shorter queryset has finished.

This creates an iterable like:

((p[0], q(0)), (p[1], q[1]), (p[2], q[2]), ..., (p[9], q[9]), (p[10], None))

Note this is an iterable of tuples, but you want a flat list. So next we use chain, using the * operator to unpack the result of zip_longest.

This creates an iterable like.

(p[0], q[0], p[1], q[1], ..., p[9], q[9], p[10], None)

That's almost what we want, but we've got Nones at the end if one queryset is shorter than the other. We can get rid of them with filter (ifilter in Python 2).

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • if there is overlap between results in p and q, what do you recommend to eliminate duplicates? – w-- Aug 23 '17 at 03:46
  • @w-- that's not part of the original problem so it would be better to ask a new question. – Alasdair Aug 23 '17 at 07:36
  • cool thanks. I've created a new question here: https://stackoverflow.com/questions/45834009/django-merge-2-querysets-in-staggered-alternating-fashion-without-duplicates – w-- Aug 23 '17 at 08:04