在给定条件的情况下递增前n个列表元素

时间:2015-12-08 17:32:51

标签: python list python-2.7 list-comprehension

我有一个列表例如

l = [10, 20, 30, 40, 50, 60]

我需要在给定条件的情况下递增列表的第一个n元素。该条件与列表无关。例如,如果n = 3,则列表l应变为:

l = [11, 21, 31, 40, 50, 60]

我知道我可以在列表的每个元素上使用for循环来完成它。但我需要做大约1.5亿次这样的操作。所以,我正在寻找一种更快的方法来做到这一点。任何帮助都非常感谢。提前致谢

4 个答案:

答案 0 :(得分:2)

您可以在列表顶部创建一个简单的数据结构,用于存储每个增量操作的开始和结束范围。在您的情况下,开始将为0,因此您可以存储结束。

这样您就不必实际遍历列表来增加元素,但您只保留在范围上执行增量,例如{0到2}和{0到3}。此外,您还可以整理一些操作,这样如果多个操作递增到相同的索引,您只需要存储一个条目。

此解决方案的最坏情况复杂性为O(q + g x qlogq + n),其中g是get操作的数量,q是更新的数量,n是列表的长度。由于我们的间隔最多可以有n个不同的结尾,因此减少到O(q + nlogn + n) = O(q + nlogn)。使用每个查询的更新的天真解决方案是O(q * l)其中l(查询的长度)可以达到给出O(q * n)的n的大小。因此,q > log n时,我们可以期待此解决方案更好。

下面的工作python示例:

def RangeStructure(object):

  def __init__(self, l):
    self.ranges = collections.defaultdict(int)
    self.l = l

  def incToPosition(self, k):
    self.ranges[k] += 1

  def get(self):
    res = self.l
    sorted_keys = sorted(self.ranges)
    last = len(sorted_keys) - 1                                                                                                                                                                                                                
    to_add = 0
    while last >= 0:
        start = 0 if last < 1 else sorted_keys[last - 1]
        end = sorted_keys[last]
        to_add += self.ranges[end]
        for i in range(start, end):
            res[i] += to_add
        last -= 1
    return res

rs = RangeStructure([10, 20, 30, 40, 50, 60])
rs.incToPosition(2)
rs.incToPosition(2)
rs.incToPosition(3)
rs.incToPosition(4)
print rs.get()

并作出解释:

  1. 在inc操作范围之后将包含(start,end,inc)形式(0,2,2),(0,3,1),(0,4,1)的元组;这些将在dict中表示为{2:2,3:1,4:1},因为开头始终为1并且可以省略

  2. get操作期间,我们确保我们只对任何列表元素进行一次操作;我们按照其终点的递增顺序对范围进行排序,并以相反的顺序遍历它们,更新包含的列表元素和要添加到后续范围的总和(to_add

  3. 按预期打印:

    [14, 24, 32, 41, 50, 60]
    

答案 1 :(得分:1)

以下是NumPy中的操作聚合实现:

initial_array = # whatever your l is, but as a NumPy array
increments = numpy.zeros_like(initial_array)
...
# every time you want to increment the first n elements
if n:
    increments[n-1] += 1
...
# to apply the increments
initial_array += increments[::-1].cumsum()[::-1]

这是O(ops + len(initial_array)),其中ops是增量操作的数量。除非你只是在列表的一小部分上做了少量的增量,否则这应该快得多。与天真的实现不同,它不允许您在应用增量之前检索元素值;如果您需要这样做,您可能需要一个基于BST或类似BST结构的解决方案来跟踪增量。

答案 2 :(得分:1)

m - 查询计数,n - 列表增加长度,O(n + m)算法思路:
因为你只需要从开始增加到某个第k个元素,你将获得增量范围。让我们的增量成对(达到位置,递增)。例如:
(1,2) - 将位置0和1增加2 如果我们试图计算位置k处的值,那么我们应该将位置大于或等于k的增量添加到位置k处的当前值。我们如何快速计算位置大于或等于k的增量之和?我们可以从列表的后面开始计算值,然后记住增量的总和 概念证明:

# list to increment
a = [1, 2, 5, 1, 6]
# (up to and including k-th index, increment by value)
queries = [(1, 2), (0, 10), (3, 11), (4, 3)]

# decribed algorithm implementation
increments = [0]*len(a)
for position, inc in queries:
    increments[position] += inc

got = list(a)
increments_sum = 0
for i in xrange(len(increments) -1, -1, -1):
    increments_sum += increments[i]
    got[i] += increments_sum


# verify that solution is correct using slow but correct algorithm
expected = list(a)
for position, inc in queries:
    for i in xrange(position + 1):
        expected[i] += inc

print 'Expected: ', expected
print 'Got:      ', got

输出:

Expected:  [27, 18, 19, 15, 9]
Got:       [27, 18, 19, 15, 9]

答案 3 :(得分:-2)

您可以使用列表推导并添加剩余列表

[x + 1 for x in a[:n]]+a[n:]