Python从另一个列表中创建列表中的元组

时间:2015-11-19 18:54:04

标签: python list tuples

假设我有这些数据:

data = [1, 2, 3, -4, -5, 3, 2, 4, -2, 5, 6, -5, -1, 1]

我需要通过元组将其分组到另一个列表中。一个元组由两个列表组成。一个是正​​数,另一个是负数。应该通过检查它是什么类型的数字来创建元组。最后的负数(我的意思是连续的负数之间没有正数)意味着,其他数字必须进入另一个元组,当它找到另一个最后的负数时,它应该创建另一个元组。

所以规则是这样的:所有找到的数字都被添加到第一个元组中,当它找到负数时,它仍然将它添加到该元组,直到它找到正数(这意味着必须创建新的元组)。

我认为展示比解释更容易。解析data后,列表应如下所示:

l = [([1, 2, 3], [-4, -5]), ([3, 2, 4], [-2]), ([5, 6], [-5, -1]), ([1], [])]

我创建了一个解决方案,但我想知道它是否非常理想。也许有可能写出一个更优雅的(我想知道性能,是否有更好的方法来编写具有最佳性能的解析器:))?

def neighborhood(iterable):
    iterator = iter(iterable)
    prev = None
    item = iterator.next()  # throws StopIteration if empty.
    for next in iterator:
        yield (prev,item,next)
        prev = item
        item = next
    yield (prev,item,None)

l = []    
pos = []
neg = []
for prev, item, next in neighborhood(data):
    if item > 0:
        pos.append(item)
        if not next:
            l.append((pos, neg))
    else:
        neg.append(item)
        if next > 0:
            l.append((pos, neg))
            pos = []
            neg = []
        elif not next:
            l.append((pos, neg))

print l

P.S。我认为if not next部分只能在主要检查后使用一次。

2 个答案:

答案 0 :(得分:8)

我首先使用itertools.groupby制作包含正/负列表的连续元组列表,然后分组成连续的对。通过利用生成器,这仍然可以通过列表一次完成:

from itertools import groupby, zip_longest

x = (list(v) for k,v in groupby(data, lambda x: x < 0))
l = list(zip_longest(x, x, fillvalue=[]))

这会将l视为:

[([1, 2, 3], [-4, -5]), ([3, 2, 4], [-2]), ([5, 6], [-5, -1]), ([1], [])]

关于上述代码的几点说明:

  • 初始分组为正/负值会传递给groupby,这应该是合理的(它的编译代码)。

  • 用于分组成对的zipping-a-generator方法在Python中是一个相当常见的习惯用法。它保证自zip保证起作用,而不是从左到右消耗迭代。

  • 在Python 2中,使用izip_longest

答案 1 :(得分:0)

你可以使用O(n)解决方案,这个解决方案不如@ajcr那么漂亮,但应该更有效率。

def pos_neg(data):
  split = []
  for r in data:
    if len(split) == 0 or (r > 0 and len(split[-1][-1]) > 0):
      split.append(([], []))

    if r < 0:
      split[-1][-1].append(r)
    else:
      split[-1][-2].append(r)

  return split

data = [1, 2, 3, -4, -5, 3, 2, 4, -2, 5, 6, -5, -1, 1]
print pos_neg(data)
#=> [([1, 2, 3], [-4, -5]), ([3, 2, 4], [-2]), ([5, 6], [-5, -1]), ([1], [])]