shanlodh
shanlodh

Reputation: 1045

How to group multiple lists into single list in a Pythonic way?

I've a function returning list from list of lists where the return list groups members of each list by index numbers. Code and example:

def listjoinervar(*lists: list) -> list:
    """returns list of grouped values from each list 
        keyword arguments:
        lists: list of input lists
    """ 
    assert(len(lists) > 0) and (all(len(i) == len(lists[0]) for i in lists))
    joinedlist = [None] * len(lists) * len(lists[0])
    for i in range(0, len(joinedlist), len(lists)):
        for j in range(0, len(lists[0])):
            joinedlist[i//len(lists[0]) + j*len(lists[0])] = lists[i//len(lists[0])][j]
    return joinedlist

a = ['a', 'b', 'c']
b = [1, 2, 3]
c = [True, False, False]
listjoinervar(a, b, c)
# ['a', 1, True, 'b', 2, False, 'c', 3, False]

Are there ways to make this more Pythonic using itertools, generators, etc? I've looked at examples like this but in my code there is no interaction b/w the elements of the individual lists. Thanks

Upvotes: 3

Views: 1092

Answers (4)

Austin
Austin

Reputation: 26039

Use itertools.chain.from_iterable + zip:

from itertools import chain

def listjoinervar(*a):
    return list(chain.from_iterable(zip(*a)))

Usage:

>>> a = ['a', 'b', 'c']
>>> b = [1, 2, 3]
>>> c = [True, False, False]
>>> listjoinervar(a, b, c)
['a', 1, True, 'b', 2, False, 'c', 3, False]

Upvotes: 7

Snorfalorpagus
Snorfalorpagus

Reputation: 3489

Using zip and list comprehension:

from typing import List, Any

def listjoinervar(*args: List[Any]) -> List[Any]:
    return [item for sublist in list(zip(*args)) for item in sublist]

Usage:

>>> a = ["a", "b", "c"]
>>> b = [1, 2, 3]
>>> c = [True, False, False]
>>> listjoinervar(a,b,c)
['a', 1, True, 'b', 2, False, 'c', 3, False]

The use of type annotations is optional.

Upvotes: 1

Malekai
Malekai

Reputation: 5011

You can do this without having to import anything, using the enumerate and max methods:

def custom_group(*args):
  biggest, result = max(args, key = lambda x: len(x)), []
  for (i, value) in enumerate(biggest):
    for arr in args:
      if len(arr) > i:
        result.append(arr[i])
  return result

You're looping through the biggest list and adding each value from each list at that index (if it exists) to the results list then moving on to the next index until the loop stops.

Using your specified arrays:

a = ["a", "b", "c"]
b = [1, 2, 3]
c = [True, False, False]

You'd call the function, like this:

print(custom_group(a,b,c))

Which should result in the following list being outputted:

["a", 1, True, "b", 2, False, "c", 3, False]

Good luck.

Upvotes: 0

gmds
gmds

Reputation: 19885

In a normal situation, I would also use itertools.chain, as in Austin's answer.

However, just for completeness, an alternative solution that does not import anything:

def join_lists(*a):
    return [element for sub in zip(*a) for element in sub]

a = ['a', 'b', 'c']
b = [1, 2, 3]
c = [True, False, False]

join_lists(a, b, c)

Output:

['a', 1, True, 'b', 2, False, 'c', 3, False]

Upvotes: 3

Related Questions