最有效的方法来循环Python子列表,同时使它们增长(插入方法)?

时间:2013-05-29 15:54:44

标签: python algorithm

我的问题是在循环中管理插入/追加方法。

我有两个长度为N的列表:第一个列表(我们称之为s)表示其中的子集,而第二个表示我想要的数量x评估。为简单起见,我们假设每个子集都呈现T个元素。

cont = 0;
for i in range(NSUBSETS):
    for j in range(T):
        subcont = 0;
        if (x[(i*T)+j] < 100):
            s.insert(((i+1)*T)+cont, s[(i*T)+j+cont]);
            x.insert(((i+1)*T)+cont, x[(i*T)+j+cont]);
            subcont += 1;
    cont +=  subcont;

当循环遍历两个列表的所有元素时,我希望当满足某个条件时(例如x[i] < 100),该元素的副本放在子集的末尾,并且然后继续循环,直到完成子集的所有原始成员的分析。保持“顺序”很重要,即在元素的最后一个元素旁边插入元素。

我认为一种方法可能是在2个计数器变量中存储子集和全局内的副本数量(参见代码):这样,我可以根据以下方式移动我正在查看的元素的索引那。我想知道是否存在一些更简单的方法,可能使用一些Python魔法。

5 个答案:

答案 0 :(得分:2)

如果想要将额外副本插入列表而不制作整个列表的完整副本,则可以使用generator expression进行尝试。在循环浏览列表时,收集要添加的匹配项。在处理每个项目时产生,然后产生每个收集的项目。

这是一个只有一个列表的简化示例,但希望它能说明这个想法。如果你喜欢我已经完成并且通过理解扩展了生成器,你只会得到一份副本。如果您只想存储或进一步分析已处理的列表(例如,将其写入磁盘),则根本无法将其存储在内存中。

def append_matches(input_list, start, end, predicate):
  # where predicate is a filter function or lambda
  for item in input_list[start:end]:
    yield item
  for item in filter(predicate, input_list[start:end]): 
    yield item

example = lambda p:  p < 100
data = [1,2,3,101,102,103,4,5,6,104,105,106]

print [k for k in append_matches (data, 0, 6, example)]
print [k for k in append_matches (data, 5, 11, example)]

[1, 2, 3, 101, 102, 103, 1, 2, 3]
[103, 4, 5, 6, 104, 105, 4, 5, 6]

答案 1 :(得分:2)

我猜你不想复制列表的愿望是基于你的C背景 - 假设它会更昂贵。在Python中,列表实际上不是列表,插入有O(n)时间,因为它们更像是向量,因此那些插入操作都是复制列表。

使用额外元素构建新副本比尝试就地更新更有效。如果你真的想要这样做,你需要编写一个包含prev / next引用的LinkedList类,这样你的Python代码才真正是C方法的副本。

最Pythonic方法不会尝试进行就地更新,因为使用值而不是引用来表达您想要的内容更简单:

def expand(origLs) :
  subsets = [ origLs[i*T:(i+1)*T] for i in range(NSUBSETS) ]
  result = []
  for s in subsets :
    copies = [ e for e in s if e<100 ]
    result += s + copies
  return result

要记住的主要事情是,解释的垃圾收集语言的基础成本模型与C非常不同。并非所有复制操作实际上都会导致数据移动,并且无法保证尝试重用相同的内存将会成功或更有效率。唯一真正的答案是在您的真实问题上尝试这两种技术并分析结果。

答案 2 :(得分:0)

我倾向于复制您的列表,然后在循环原件时,当您遇到插入标准时插入您需要它的位置的副本。然后,您可以输出复制和更新的列表。

答案 3 :(得分:0)

我认为找到了一个简单的解决方案。 我从最后一个子集向后循环,将副本放在每个子集的末尾。这样,我避免遇到“新”元素并摆脱计数器和 similia

for i in range(NSUBSETS-1, -1, -1):
    for j in range(T-1, -1, -1):
        if (x[(i*T)+j] < 100):
            s.insert(((i+1)*T), s[(i*T)+j])
            x.insert(((i+1)*T), x[(i*T)+j])

答案 4 :(得分:-1)

一种可能性是使用numpy的高级索引,通过构建原始列表的“复制”索引列表,并将其添加到代表每个索引的每个索引/切片列表,提供将元素复制到子集末尾的错觉。子集。然后你将最后的所有索引/切片列表组合在一起,并使用最终的索引列表来访问你的所有项目(我相信也有支持这样做的生成器风格,你可能会发现它有用作高级索引/切片返回副本而不是视图)。根据要复制的标准的元素数量,这应该是相当有效的,因为每个子集将其索引作为切片对象,减少了跟踪所需的索引数量。