1

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

我有两个长度列表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 魔法。

4

5 回答 5

2

如果想法是将您的额外副本插入列表而不制作整个列表的完整副本,您可以使用生成器表达式尝试此操作。当您循环浏览您的列表时,收集您想要附加的匹配项。在处理每个项目时产生它,然后也产生每个收集的项目。

这是一个只有一个列表的简化示例,但希望它能说明这个想法。如果你像我所做的那样做,你只会得到一份副本,并用理解来扩展生成器。如果您只是想存储或进一步分析已处理的列表(例如,将其写入磁盘),您根本不可能将它放在内存中。

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]
于 2013-05-30T06:28:50.763 回答
2

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

使用额外元素构建新副本比尝试就地更新更有效。如果你真的想这样做,你需要编写一个 LinkedList 类来保存 prev/next 引用,以便你的 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 非常不同。并非所有复制操作都会导致数据移动,并且不能保证尝试重用相同的内存会成功或更高效。唯一真正的答案是在您的实际问题上尝试这两种技术并分析结果。

于 2013-05-30T09:28:04.560 回答
0

我认为已经找到了一个简单的解决方案。我从最后一个子集向后循环,将副本放在每个子集的末尾。这样,我避免遇到“新”元素并摆脱 counters 和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])
于 2013-05-30T05:26:31.093 回答
0

我倾向于复制您的列表,然后在遍历原件时遇到一个标准,将您插入到您需要的位置的副本中。然后,您可以输出复制和更新的列表。

于 2013-05-29T16:02:29.840 回答
-1

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

于 2013-05-29T19:02:42.790 回答