2017-04-14 79 views
0

有没有一种方法来使用标准python 2.7(C++ STL std :: partition style)通过谓词分区列表?像group_byitertools但不包括额外的数组?我需要递归地将数组分为两组,基于可变参数条件,并且受RAM的限制。Python - 在位列表分区

我所寻找的是一个函数,如:

partitionCPPStyle(data, startIndex, endIndex, condition)

这将导致具有满足在开始条件的所有元素,并返回不fullfil第一个元素的索引列表data[startIndex:endIndex]条件。没有副本,尽可能少使用额外的内存。

我已经结束了写我自己的实现:

def partitionInPlace(data, startIndex, endIndex, predicate): 
    swapIndex = endIndex 
    index = startIndex 
    while(index < swapIndex): 
     if not predicate(data[index]): 
      temp = data[swapIndex] 
      data[swapIndex] = data[index] 
      data[index] = temp 
      swapIndex = swapIndex-1 
     else: 
      index = index+1 
    return index 

有没有更有效的方式来做到这一点?

+0

迭代器工具不会复制列表或我完全错误?但是,如果你计划删除列表中的项目,你将不得不创建一个新的列表,看看列表是不可变的,不能改变。也许看看'dicts'或[ctype.array](https://docs.python.org/2/library/ctypes.html#arrays)s - 也许你可以用这些做些什么? – Torxed

+0

@Toxxed列表是可变的。 – roganjosh

+0

@roganjosh对不起,你说得对。我在头脑中混合了'tuple'的列表。 – Torxed

回答

0

这是比较容易实现的 - 但既然你有“条件”(我将使用这里的术语“断言”),有并发症:对于没有复制可言,所形成的结构的唯一途径可以“知道”一个项目是否在访问时检查它 - 这意味着你的索引中会出现“漏洞”。

这很容易理解给出的例子:

a = list(range(20)) 
b = SlicedList(a, slice(10, 20), predicate=lambda x: x%2 
len(b) # will correctly report (5) 
b[0] # will raise ValueError as "10" fails the predicate 
# so, 0-9 are valid indexes for "b", but only the contents 
# that attend the predicate will actually return a value 
# you can safely iterate on b with a "for", though: 
for item in b: 
    print(item) # (11, 13, 15, 17, 19) 

迭代,但是,它应该很好地工作。

try: 
    from collections.abc import MutableSequence 
except ImportError: 
    from collections import MutableSequence 


class SlicedList(MutableSequence): 
    def __init__(self, data, slice=None, predicate=None): 
     self.data = data 
     if not slice: 
      slice = __builtins__.slice(0, len(data), 1) 
     self.slice = slice 
     self.predicate = predicate 

    def __getitem__(self, index): 
     if index < 0: 
      raise NotImplementedError("Can't use negative indexes on Sliced lists") 
     real_index = self.slice.start + index * (self.slice.step or 1) 
     item = self.data[real_index] 
     if self.predicate and not self.predicate(item): 
      raise ValueError("Item at position {} does not attend the predicate".format(index)) 
     return item 

    def __setitem__(self, index, value): 
     ... 

    def __delitem__(self, index): 
     ... 

    def __len__(self): 
     if not self.predicate: 
      start, stop, step = self.slice.indices(len(data)) 
      return (stop - start) // (step or 1) 
     count = 0 
     for i in range(self.slice.start, self.slice.stop, self.slice.step or 1): 
      if self.predicate(self.data[i]): 
       count += 1 
     return count 

    def __iter__(self): 
     for i in range(self.slice.start, self.slice.stop, self.slice.step or 1): 
      value =self.data[i] 
      if not self.predicate or self.predicate(value): 
       yield i 

    def insert(self, position, value): 
     ... 

另一个提示你是要尽快退出Python 2.7版 - 所有的现代库和框架运行好的关于Python 3和Python 2是变得非常老化,这些天。下面的代码可以同时工作,但我必须为此做出规定。

0

它只是一个简单的快速排序,你可以做你自己的

def partitionCPPStyle(data, a, b, condition): 
    if a>= b:return 
    left = a 
    right = b 
    while left <= right: 
     while left <= right and condition(data[left]): 
      left += 1 
     while left <= right and not condition(data[right]): 
      right -= 1 
     if left <= right: 
      data[left], data[right] = data[right], data[left] 
      left, right = left + 1, right - 1 

def less7(num): 
    return num < 7 
if __name__ == '__main__': 
    data = [2,34,6,1,3232,32] 
    partitionCPPStyle(data, 0, 5, less7) 
    print(data) 

它看起来像c.but很容易和好。