Search code examples
pythonlistlist-comprehensionpython-itertools

Python: Linking Lists Together


Suppose I have a list where each index is either a name, or a list of rooms the preceding name index reserved.

[["Bob"],["125A, "154B", "643A"],["142C", "192B"], ["653G"], 
["Carol"], ["95H", 123C"], ["David"], ["120G"]]

So in this case, Bob has the rooms: 125A, 154B, 643A, 152C, 192B, and 653G reserved, etc.

How do I construct a function which would make the above into the following format:

[["Bob", "125A, "154B", "643A", "142C", "192B", "653G"], ["Carol"... 

Essentially concatenating [name] with all the [list of room reservations], until the next instance of [name]. I have a function which takes a list, and returns True if a list is a name, and False if it is a list of room reservations, so effectively I have:

[True, False, False, False, True, False, True False] for the above list, but not sure how that would help me, if at all. Assume that if a list contains names, it only has one name.


Solution

  • Given the following method

    def is_name(x):
      return # if x is a name or not
    

    a simply and short solution is to use a defaultdict


    Example:

    from collections import defaultdict
    
    def do_it(source):
      dd = defaultdict(lambda: [])
      for item in sum(source, []): # just use your favourite flattening method here
        if is_name(item):
          name = item
        else:
          dd[name].append(item)
      return [[k]+v for k,v in dd.items()]
    
    for s in do_it(l):
      print s
    

    Output:

    ['Bob', '125A', '154B', '643A', '142C', '192B', '653G']
    ['Carol', '95H', '123C']
    ['David', '120G']


    Bonus:

    This one uses a generator for laziness

    import itertools 
    
    def do_it(source):
      name, items = None, []
      for item in itertools.chain.from_iterable(source):
        if is_name(item):
          if name: 
            yield [name] + items
            name, items = None, []
          name = item
        else:
          items.append(item)
      yield [name] + items