16

私は現在 F# を学んでおり、yield!(yield-bang) 演算子が大好きです。その名前だけでなく、もちろんそれが何をするかについても。

演算子を使用すると、yield!基本的に、シーケンス式からシーケンスのすべての要素を生成できます。これは、列挙子を作成するのに役立ちます。私は定期的に大きくて複雑な列挙子に遭遇するので、それらを分割して単純な列挙子から構成するために使用できる戦略に興味があります。

残念ながら、このyield!演算子は C# では使用できません。私が理解している限り、それが何をするかは似てforeach (var x in source) yield x;いますが、私が読んでいる本 ( Petricek's Real World F# - Manning ) は、それがより良いパフォーマンスを持っていることを示唆しています...

  • では、ここで F# コンパイラは正確に何を行うのでしょうか? (はい、Reflector を使用して見ることもできますが、メカニズムの詳細な説明が必要です)。

C# で同様の構成を実現するために、複数の方法を検討しましたが、どれもyield!演算子ほど簡潔ではなく、複雑さもわかりません。私の BigO 番号が正しい場合、誰かが入力を提供してもらえますか?

  • 列挙子を複数のプライベート列挙子に分解し、パブリック列挙子から各要素を生成します。

    foreach (var x in part1()) yield x
    foreach (var x in part2()) yield x
    

    これにより、事実上、各要素で「二重の利回り」が得られます。それはO(2n)ですか?(またはさらに悪い?)とにかく、このアプローチを使用yield break;すると、サブパーツのいずれからも使用できなくなります。

  • 列挙子を複数のプライベート列挙子に分解し、パブリック列挙子からすべてのプライベート列挙子を連結します。

    return part1().Concat(part2())
    

    Concat()上記で概説した方法で実装されているため、これは前述のソリューションと変わらないと思います。

他のオプションはありますか?

4

3 に答える 3

7

foreach... yield return現在のバージョンのC#では、と以外のオプションはないと思いますConcat。C#に演算子があると便利だと思いますyield!。これにより、特定の構成がはるかにエレガントになりますが、この機能がなくても簡単に実行できるため、この機能が「必須」リストに含まれることはないと思います。

新しい構成を紹介するこのMS研究論文に興味があるかもしれませんyield foreach

IEnumerable<XmlNode> Traverse(XmlNode n)
{
    yield return n;
    foreach (XmlNode c in n.ChildNodes)
        yield foreach Traverse(c);
}

複雑さについてのあなたの質問に関して:どちらの場合もそれはO(n)です。O(2n)は、 O(n)(線形)と同じ複雑さを示すため、使用されません。現在のC#機能でそれ以上のことができるとは思いません...

于 2010-08-17T08:35:36.070 に答える
6

コンパイラがyield!演算をどのように変換するかに関して、Thomas Levesque が回答で引用した論文では、セクション 4.3 で 1 つの実装手法が示されています (特に、図 7 ~ 9 にまたがる例は、一般的な戦略を示しています)。C#のイテレータブロック内からこれを行う良い方法はないと思います.提案された解決策を理解しているので、再帰的に使用すると、どちらも2次動作になる可能性があります. サブクラスを手動で作成しNestedEnumerable<T>てパフォーマンス上の利点を得ることができますが、これは通常の反復子ブロックを使用する場合に比べて非常に見苦しくなります。

于 2010-08-17T13:36:01.013 に答える
4

yield!C#に直接対応するものはありません。foreach現在、との組み合わせで立ち往生していますyield return

ただし、IIRC、LINQは同様の機能、つまりクエリ演算子を提供します。これは、複数の句SelectManyとしてC#に変換されます。from .. in ..

(2つの異なる概念を混同しないことを望んでいますが、IIRCは両方ともyield!SelectMany本質的に「フラット化」された投影です。つまり、オブジェクトの階層はリストに「フラット化」されます。)

于 2010-08-17T08:41:25.710 に答える