2012-05-16 82 views
10

我有一個列表的列表,使每個內部列表的長度是1或n(假設n> 1)。Python列表轉置和填充

>>> uneven = [[1], [47, 17, 2, 3], [3], [12, 5, 75, 33]] 

我要轉的名單,但不是截斷較長的列表(如zip)或None填充短名單,我想用自己的奇異值,填補了短名單。換句話說,我想獲得:

>>> [(1, 47, 3, 12), (1, 17, 3, 5), (1, 2, 3, 75), (1, 3, 3, 33)] 

我可以用幾個迭代做到這一點:

>>> maxlist = len(max(*uneven, key=len)) 
>>> maxlist 
4 
>>> from itertools import repeat 
>>> uneven2 = [x if len(x) == maxlist else repeat(x[0], maxlist) for x in uneven] 
>>> uneven2 
[[1, 1, 1, 1], [47, 17, 2, 3], [3, 3, 3, 3], [12, 5, 75, 33]] 
>>> zip(*uneven2) 
[(1, 47, 3, 12), (1, 17, 3, 5), (1, 2, 3, 75), (1, 3, 3, 33)] 

但有沒有更好的方法嗎?我真的需要提前知道maxlist才能完成此任務嗎?

+1

你可以模擬'itertools.izip_longest',只是使用序列代替'fillvalue'的最後一個值時,該序列被耗盡。 –

+0

@ChrisMorgan是正確的看到這個鏈接http://docs.python.org/library/itertools.html也許你也可以使用其他一些功能。 –

回答

7

你可以永遠重複一個元素列表:

uneven = [[1], [47, 17, 2, 3], [3], [12, 5, 75, 33]] 

from itertools import repeat 

print zip(*(repeat(*x) if len(x)==1 else x for x in uneven)) 
+0

這是非常有用的,因爲n = 1的內部列表已經制造完成。現在我已經重構了,所以列表是'[repeat(1),[47,17,2,3],repeat(3),[12,5,75,33]]',我可以'zip( *不均勻)'。 – kojiro

4

你可以使用itertools.cycle()代替:

>>> from itertools import cycle 
>>> uneven3 = [x if len(x) != 1 else cycle(x) for x in uneven] 
>>> zip(*uneven3) 
[(1, 47, 3, 12), (1, 17, 3, 5), (1, 2, 3, 75), (1, 3, 3, 33)] 

這意味着你不需要知道maxlist提前。

0

我真的很喜歡@ chris-morgan的模擬itertools.izip_longest的想法,所以當我終於有了靈感時,我寫了一個izip_cycle函數。

def izip_cycle(*iterables, **kwargs): 
    """Make an iterator that aggregates elements from each of the iterables. 
    If the iterables are of uneven length, missing values are filled-in by cycling the shorter iterables. 
    If an iterable is empty, missing values are fillvalue or None if not specified. 
    Iteration continues until the longest iterable is exhausted. 
    """ 
    fillvalue = kwargs.get('fillvalue') 
    counter = [len(iterables)] 
    def cyclemost(iterable): 
     """Cycle the given iterable like itertools.cycle, unless the counter has run out.""" 
     itb = iter(iterable) 
     saved = [] 
     try: 
      while True: 
       element = itb.next() 
       yield element 
       saved.append(element) 
     except StopIteration: 
      counter[0] -= 1 
      if counter[0] > 0: 
       saved = saved or [fillvalue] 
       while saved: 
        for element in saved: 
         yield element 
    iterators = [cyclemost(iterable) for iterable in iterables] 
    while iterators: 
     yield tuple([next(iterator) for iterator in iterators]) 

print list(izip_cycle([], range(3), range(6), fillvalue='@'))