我正在研究这篇文章提出的问题:Fast way to remove a few items from a list/queue
基本上我想做的就是在C中实现for循环.for循环需要访问生成器并能够删除数组的元素(并递增整数)。我身上的东西告诉我这很难,但另一部分说它可以在几分钟内完成。
我没有编写高级C的经验(我为微控制器编写了代码),以及ctypes和其他c->的教程。 python似乎正在解决更棘手的问题。
def forfilt():
marked = (i for i, x in enumerate(b) if tokeep(x))
shift = 0
for n in marked:
del b[n - shift]
shift += 1
我问两个问题:
这很难吗?
你有什么指针/想自己编写代码吗? :d
这实际上对我来说似乎是一个相当重要的问题。我不知道有什么方法可以快速完成原始问题的要求。我想如果你知道答案,那么问题就是无效。
答案 0 :(得分:3)
如果您只需要删除for循环开销,那么在Cython(pip install cython
)中定义for循环变量的类型就足够了。这是Cython remove_inplace_senderle2()
中修改后的delitems.pyx
:
#cython: boundscheck=False, wraparound=False
import cython
@cython.locals(end=cython.Py_ssize_t, i=cython.Py_ssize_t)
def remove_inplace_senderle2(L, keep):
end = 0
for i in range(len(L)):
x = L[end] = L[i]
if keep(x):
end += 1
del L[end:]
for i in range(len(L))
转换为经典的C循环:for (i=0; i < L_length; ++i)
,其开销与keep()
的函数调用开销相形见绌。
注意:纯Python中的上述函数可能比L = filter(keep, L)
(或listcomp)慢。
有关如何编译和使用Cython的简单示例,请参阅gcd()
function。
答案 1 :(得分:2)
这取决于简单是多么简单。是的,只要输入是数组,就可以将此特定函数写为就地内存移动。
size_t for_filt( my_struct *b, size_t n ) {
my_struct *src_pen, *dst_pen;
for ( src_pen = dst_pen = b;
src_pen != b + n;
++ src_pen ) {
if ( tokeep( src_pen ) ) {
memmove( dst_pen ++, src_pen, sizeof (my_struct) );
}
}
return dst_pen - b; /* return number of elements in resulting array */
}
C ++标准库将上述功能简化为单行:
n = std::remove_if( b, b+n, std::not1( tokeep ) ) - b;
该函数将使用除数组之外的结构,但n = … - b;
是特定于数组的。
答案 2 :(得分:2)
针对CPython C-API编写C代码比在没有这种API支持的情况下编写C代码要愉快得多。然而,它主要是构建和链接过程并且完成所有设置,这可能相当繁琐。一旦你有一个C扩展,添加它并不太困难(虽然仍然有一些摆弄,以便在Python级别正确地暴露事物并确保所有引用计数都正确)。
像Cython这样的其他静态编译工具类似的设置成本相对较高,以使编译的扩展首先工作,但是一旦已经存在就更容易使用。
关于您的具体问题,通过将列表理解方法与filter
内置(或其Py3k等效,functools.filter
)进行比较,您链接的问题的海报已经证明了将循环代码放入C - native循环的效果是内置迭代和缩减函数的主要优点之一,如sum
,any
,all
,{{ 1}}和map
。
删除Python级别循环开销可能是两种方法(列表理解与过滤器调用)性能差异的大部分差异造成的。