【发布时间】:2013-05-06 21:58:20
【问题描述】:
如果事先不知道最终结果的数量,那么在 R 中循环收集结果的惯用方法是什么?这是一个玩具示例:
results = vector('integer')
i=1L
while (i < bigBigBIGNumber) {
if (someCondition(i)) results = c(results, i)
i = i+1
}
results
这个例子的问题是(我假设)它将具有二次复杂度,因为向量需要在每次追加时重新分配。 (这是正确的吗?)我正在寻找避免这种情况的解决方案。
我找到了Filter,但它需要预先生成1:bigBigBIGNumber,我想避免这种情况以节省内存。 (问题:for (i in 1:N) 是否也预先生成了1:N 并将其保存在内存中?)
我可以制作像这样的链表:
results = list()
i=1L
while (i < bigBigBIGNumber) {
if (someCondition(i)) results = list(results, i)
i = i+1
}
unlist(results)
(请注意,这不是串联。它正在构建一个类似list(list(list(1),2),3) 的结构,然后用unlist 展平。)
还有比这更好的方法吗?通常使用的惯用方式是什么? (我对 R 很陌生。)我正在寻找有关如何解决此类问题的建议。欢迎提出关于紧凑(易于编写)和快速代码的建议! (但我想专注于快速和内存效率。)
【问题讨论】:
-
c函数用于扩展向量或列表。如果您可以估计大小,那么使用vector("integer", size)进行分配将有助于降低扩展成本。 -
@DWin 是否有现有的工具可以按需以智能方式扩展阵列? (例如,一旦达到其容量,将预分配数组的大小加倍,并避免二次复杂度)
-
@Szabolcs,您为什么认为用
list替换c会有所帮助?除非您预先分配一个列表,否则同样的问题仍然存在,不是吗? -
@Arun 注意
c连接(触发重新分配向量),而list我正在构建一个类似list(list(list(1),2),3)的结构,一个链表。当放入循环时,后者具有线性复杂度,前者具有二次复杂度。您可以通过一个小型基准轻松验证这一点:将要附加的元素数量加倍,list的时间加倍,c的时间几乎翻了两番。这意味着对于“足够大”的结果,list方法总是更快。当我写这个问题时,我没有意识到在这种情况下“足够大”...... -
现在,我希望 this answer 可能会有所帮助,因为 R 列表就像哈希映射数据结构..