2

请参阅以下与我的情况相似的伪代码片段:

function foo () {
  for ( velocity=0; velocity<100; velocity++ ) {
    root1 = computeRoot1();
    root2 = computeRoot2();
    // do a bunch of computation with root1
    // if result of computation is undesirable, do computations again with root2 
  }

所以,基本上我想在for循环体中进行计算root1,然后root2ifroot1的计算结果无效。

我的第一直觉是显而易见的方法,将计算包装在帮助函数中,但我不确定这是最清晰的方法。我正在尝试在我的代码中很好地配置信息,并且对最多执行两次(每次迭代)的代码的函数调用会破坏该目标,而不会为我的代码提供大量的简洁性。

我在想可能是一个for循环,例如:

for ( root=root1; root1IsInvalid==true || bothRootsInvalid==true; root=root2 )

while具有类似功能的。但我当然愿意接受其他建议

作为阅读此代码的人,哪种方法对您来说最易读和简洁?

顺便说一句,我正在用 JavaScript 编写这个特定的函数,但是与语言无关的解决方案会很棒。

编辑:澄清的代码片段

4

2 回答 2

3

您有几种基本方法:

  1. 将值放入一个数组并使用for循环对数组中的每个项目运行相同的代码,可能会在满足某些条件时停止迭代。
  2. 创建一个执行计算的函数,然后只编写代码调用第一个函数,然后是第二个函数,依此类推。
  3. 创建一个while循环并重复您的代码,直到满足某些条件。

第一个选项更容易扩展到 N 个项目。对于两个项目,第二个选项可能更简单。

您可以使计算函数成为本地函数(在您当前正在执行的函数中声明和使用),这样它就不会添加到全局命名空间中,并且您的代码仍然更加封装。

我也不确定你打算用这条线做什么:

root1, root2 = computeRoots();

但是,它只是将值分配给root2,看起来您可能希望var在这些之前将它们定义为局部变量。

于 2012-12-31T04:49:10.923 回答
1

如果 Eager 评价没问题,你可以把你的根收集到一个数组中,roots.filter(isinvalid)用来取出无效的;然后只需使用结果数组中的第一项。

如果您需要惰性求值,您可以将其推广为一个函数,该函数对数组中的函数进行惰性求值,直到找到非空结果:

// call fn on items in arr until fn returns non-null
// returns [item, result]
// if result===false, no true value was returned
function firstNotNull(fn, arr) {
    var i, length, item, result=null;
    for (i = 0, length=arr.length; i < length; i++) {
        item = arr[i];
        result = fn(item);
        if (result!==null) {
            break;
        }
    }
    return [item, result];
}


function rootComputations(root) {
    var computationResult = null;
    if (root==1) {
        computationResult = 1;
    }
    return computationResult;
}

function computeRoots() {
    return [0,1];
}

function foo() {
    var velocity, roots, root, result, computations;
    for (velocity = 0; velocity < 100; velocity++) {
        roots = computeRoots();
        computations = firstNotNull(rootComputations, roots);
        console.log(computations);
        root = computations[0];
        result = computations[1];
    }
}

foo();

firstNotNull()您可以进一步概括:

// call fn on items in arr until cond(fn(item)) returns true
// returns [item, fn(item)], or null if unsatisfied
function firstSatisfying(cond, fn, arr) {
    var i, length, item, fnitem, result=null;
    for (i = 0, length=arr.length; i < length; i++) {
        item = arr[i];
        fnitem = fn(item);
        if (cond(fnitem)) {
            result = [item, fnitem];
            break;
        }
    }
    return result;
}

var firstNotNull = firstSatisfying.bind(null, function(item){return item!==null;});

您现在有了一个通用函数,用于获取满足您想要的任何条件的事物列表中的第一个。

ECMAScript 5 添加了许多方法,使得在数组上的急切函数式应用程序变得更加容易,但是 Javascript 没有任何用于惰性求值的本机工具。如果这是您认为您经常需要的东西,请考虑使用stream.js,它提供了一种“流”数据类型以及用于部分应用的方法。使用 stream.js,您的逻辑将如下所示:

// rootStream should be a function which returns a Stream
// It should construct a stream with the first root produced
// and a function that returns the remaining roots.
// Since I don't know how you get your roots, I'll use a stupid example:
function rootStream() {
    return new Stream(0, function(){
        return new Stream(1);
    });
}

function isvalid(root) {
    return root===1;
}

Stream.range(0,100)
.walk(function(v){
    //v doesn't seem to be used?
    var firstvalid = rootStream().filter(isvalid).head();
    console.log(firstvalid);
});
于 2012-12-31T05:44:40.067 回答