web-dev-qa-db-ja.com

「初期化ステップ」が「更新ステップ」と同じであるときにforループでの重複を回避するにはどうすればよいですか?

私はforループで重複したコードを書く必要がある状況をよく見つけます。この場合、「初期ステップ」は「更新ステップ」と同じです。

_// duplicate `next()`
for (let x = next(); p(x); x = next()) {
  f(x)
}

// the same in a while loop 
let x = next()
while (p(x)) {
  f(x)
  x = next()
}
_

next()が短い場合はそれほど問題ではありませんが、多くの場合はそうではありません。

_// problem is evident when next is long or even inline
let x = mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw())
while (p(x)) {
  f(x)
  x = mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw())
}

_

この状況にどのように対処できますか?

4
golopot

複雑な更新手順を繰り返さないようにする一般的な方法はいくつかあります。

  1. ラムダを使用します。

    auto g = [&]{ return mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw()); };
    for (auto x = g(); p(x); x = g(x))
        f(x);
    
  2. ダミーの初期化を使用して、条件に割り当てます。

    auto x = dummy;
    while (p(x = mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw())))
        f(x);
    

    コンマ演算子を使用したバリアント:

    auto x = dummy;
    while (x = mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw()), p(x))
        f(x);
    
  3. breakで無限ループを使用する:

    for (;;) {
        auto x = mmmmm(rewqreqw(rewqrqew()), rewqrewq(), rewqreqw());
        if (!p(x)) break;
        f(x);
    }
    

yourの場合、どちらが最適に見えますか?
あなたが決める。

4
Deduplicator

使用している言語はわかりませんが、多くの言語には、シーケンスの次の要素を生成する関数を呼び出して、forループやwhileループよりも正確な方法で抽象化されています。それはしばしばイテレータまたはジェネレータと呼ばれます。

たとえば、Scalaでは次のように記述できます。

Iterator.continually(next()).takeWhile(p).map(f)

言語が高階関数をサポートしている場合は、独自の抽象化を簡単に作成できます。また、OOP言語でgetNexthasNext関数などのインターフェースを実装することで実装されることもあります。

1
Karl Bielefeldt