Language agnostic 是否提取调用以从for头确定数组/字符串的长度?

Language agnostic 是否提取调用以从for头确定数组/字符串的长度?,language-agnostic,for-loop,complexity-theory,Language Agnostic,For Loop,Complexity Theory,我最近注意到我的一个同事在做 int len = foo.length(); for (int i = 0; i < len; ++i) doStuff(foo[i]); int len=foo.length(); 对于(int i=0;i

我最近注意到我的一个同事在做

int len = foo.length();
for (int i = 0; i < len; ++i)
    doStuff(foo[i]);
int len=foo.length();
对于(int i=0;i
我知道这在C语言中被认为是良好的实践,其中strlen()使用O(字符串的长度)。但我希望较新的语言(比如Java或Python)将字符串的长度存储在字符旁边,从而允许length()在O(1)中运行。我通常写:

for (int i = 0; i < foo.length(); ++i)
    doStuff(foo[i]);
for(int i=0;i
保存一行代码。但我的同事让我想。。。。这真的是一种好的做法,还是期望O(1)行为是不合理的


(作为一个相关问题:现代编译器现在不能自动从for头内部提取strlen()调用吗?

这些语句实际上是两个不同的语句

int len = foo.length(); // Will run once
for (int i = 0; i<len;++i)

这仍然为您节省了一行。

首先,调用函数foo.length()。在任何情况下,循环的每次迭代都需要比使用临时变量存储调用foo.length()的结果更多的资源

此外,在重构代码时,使用代码可能会导致错误。例如,这个循环永远不会结束:

for (int i = 0; i < foo.length(); ++i)
{
    doStuff(foo[i]);

    // few line of code, written another man
    doWork(foo); // Passing by reference
}

void doWork(Foo fooObj)
{
    // some work

    fooObj.Add(new SomeObject());
}
for(int i=0;i
这不是一个语言不可知论。这取决于编译器的智能程度。如果可以显式地声明长度是常量,则整个循环可以内联,因此根本不会发生任何测试。说到Java,我敢打赌编译器可以变得相当智能,所以您不必太显式。关于java.lang.String预计算其长度,您是对的。当涉及到复杂性时,定义要计算的重要操作是可行的。严格地说,在图灵机上,为了找到输入的结尾($),你必须是O(n)。

我意识到了细微的语义差异。但基本问题是,对于字符串和数组等基本数据结构,将length()调用放在头的前面是否有意义。我认为不会,因为我希望length()无论如何都是O(1)。(是的,我知道对于列表、树或任何我不应该期望O(1)的东西,因此我将自己限制在数组和字符串上)。如果你接受我的最后一行代码和你的同事写的代码,应该没有什么区别,否则我就不知道答案了。但是,将您提供的代码与同事的代码进行比较是不同的,因为在您的代码中,每次迭代都会调用
foo.length()
,而同事的
foo.length()
只调用一次。
for (int i=0, len=foo.length();i<len;++i)
for (int i = 0; i < foo.length(); ++i)
{
    doStuff(foo[i]);

    // few line of code, written another man
    doWork(foo); // Passing by reference
}

void doWork(Foo fooObj)
{
    // some work

    fooObj.Add(new SomeObject());
}