根据条件在嵌套列表中插入缺少的元素 - Python

时间:2013-12-11 10:04:23

标签: python insert nested tuples

我有嵌套列表,

a = [(2,0),(3,0),(4,2),(10,3),(11,5)]

我想要做的是在位置(0,n)添加内部元组n,其中na中缺失元素的位置。每个内部列表中的第二个元素应以1为增量增加,如果存在间隙,则应在该间隙处插入(0,n)

因此列表a的预期结果是:

a_out = [(2,0),(3,0),(0,1),(4,2),(10,3),(0,4),(11,5)]

即由于a中的第一个和第二个元素是(3,0)(4,2),因此在它们之间插入(0,1)

我的解决方案有效,但我想知道是否有更多的pythonic方式来实现它?我一直在查找Python的itertools库,但我找不到简洁的解决方案。

到目前为止我的代码是:

l1 = [n[1] for n in a]
l2 = range(max(l1)+1)
l3 = [n for n in l2 if not in l1]


zeros = [0]*len(l3)
inserts = zip(zeros,l3)
a_full = a + inserts

a_out = sorted(a_full, key = itemgetter(1))

有人能建议更好的解决方案吗?

编辑:

通常,可能有许多元素具有相同的第二内部元素(例如(2,0)中出现(3,0)a。但是,我可以将这些归为一组,而不失一般性。

然后可以将嵌套列表a表示为

a_sum = [(5,0),(4,2),(10,3),(11,5)]

使用代码,

a_group = [sum([x for x, y in group]) for key, group in groupby(a, key=itemgetter(1))]

a_sum = zip(output,list(set(l1)))

编辑II:

a的长度始终为600,但根据研究的进展情况,这可能会增加到10 ** 3。

6 个答案:

答案 0 :(得分:2)

您可以在O(n)中的嵌套列表推导中执行此操作。只需在嵌套部分中添加任何缺失的条目。

>>> a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
>>> [k for i,j in enumerate(a, 1) for k in [j] + [(0,n) for n in range(j[1]+1, a[min(i, len(a)-1)][1])]]
[(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]

>>> [k for i,j in zip(a, a[1:]) for k in [i] + [(0,n) for n in range(i[1]+1, j[1])]] + a[-1:]
[(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]

如果a很大,可以通过在其上使用额外的迭代器来避免a[1:]切片

>>> a_iter = iter(a); next(a_iter)
(2, 0)
>>> [k for i,j in zip(a, a_iter) for k in [i] + [(0,n) for n in range(i[1]+1, j[1])]] + a[-1:]
[(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]

答案 1 :(得分:1)

此版本将(2,0)和(3,0)组合成(5,0),如评论中所允许的

>>> from collections import defaultdict
>>> D = defaultdict(int)
>>> a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
>>> for i,j in a:
...     D[j]+=i
...
>>> [(D[n], n) for n in range(a[0][1], a[-1][1]+1)]
[(5, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]

答案 2 :(得分:0)

a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
i = 1
while i < len(a):
  if a[i-1][1] + 1 < a[i][1]:
    a.insert(i, (0, a[i-1][1]+1))
  i += 1

但是你可能想要考虑一般使用不同的数据类型,也许defaultdict 似乎在所有没有真正的地方都有一个默认值(在你的情况下为0)存储。

答案 3 :(得分:0)

import operator
a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
seen = set([item[1] for item in a])
inserts = [(0, item) for item in range(max(seen)) if item not in seen]
a_out = sorted(a + inserts, key=operator.itemgetter(1))
print(a_out)

产量

[(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]

上述O(n log n)解决方案会保留您发布的代码的行为。如果我们还可以假设a元组中的第二项总是不减少,那么有更好的O(n)(一次通过)解决方案,例如:< / p>

a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
result = a[:1]
for item in a[1:]:
    result.extend(
        [(0,i) for i in range(result[-1][1]+1, item[1])] + [item])

答案 4 :(得分:0)

为什么不使用一个小而可读的功能:

def fill(seq):
    """
    >>> list(fill([(2, 0), (3, 0), (4, 2), (10, 3), (11, 5)]))
    [(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]
    """
    prev = None
    for value, key in seq:
        if prev != None:
            while key > prev + 1:
                prev += 1
                yield (0, prev)
        yield (value, key)
        prev = key

if __name__ == '__main__':
    import doctest
    doctest.testmod()

答案 5 :(得分:0)

>>> from collections import defaultdict
>>> D = defaultdict(list)
>>> a = [(2,0),(3,0),(4,2),(10,3),(11,5)]
>>> for i,j in a:
...     D[j].append(i)
...
>>> [(z, n) for n in range(a[0][1], a[-1][1]+1) for z in D[n] or [0]]
[(2, 0), (3, 0), (0, 1), (4, 2), (10, 3), (0, 4), (11, 5)]