8

C# では、次のようなことができます。

public IEnumerable<T> GetItems<T>()
{
    for (int i=0; i<10000000; i++) {
        yield return i;
    }
}

これは、その長さのコレクションをメモリに割り当てることなく、1000 万個の整数の列挙可能なシーケンスを返します。

Rubyで同等のことを行う方法はありますか? 私が対処しようとしている特定の例は、列挙される値のシーケンスへの長方形配列の平坦化です。戻り値はArrayorSetである必要はありませんが、インデックスではなく、順番にのみ反復/列挙できるある種のシーケンスです。したがって、シーケンス全体を同時にメモリに割り当てる必要はありません。.NET では、これはIEnumerableIEnumerable<T>です。

私は .NET の用語に精通しているため、Ruby の世界で使用されている用語を明確に説明していただけると助かります。

編集

おそらく、私の最初の質問は十分に明確ではありませんでしyieldた.C#とRubyでは意味が大きく異なるという事実が、ここでの混乱の原因だと思います.

メソッドでブロックを使用する必要があるソリューションは必要ありません。実際の戻り値を持つソリューションが必要です。戻り値により、シーケンスの便利な処理 (フィルタリング、射影、連結、圧縮など) が可能になります。

これは、私がどのように使用するかの簡単な例ですget_items:

things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing }

IEnumerableC# では、を使用するメソッドを返すとyield return、コンパイラは、この動作に対応するための舞台裏で有限状態マシンを生成します。Ruby の継続を使用して同様のことを達成できるのではないかと思いますが、例を見たことがなく、これがどのように行われるかについては明確ではありません。

Enumerableこれを達成するために私が使用する可能性は確かにあるようです。簡単な解決策はArray(モジュールを含むEnumerable)ですが、遅延して提供し、メモリスパイクをまったく回避できる場合は、メモリ内に N 個のアイテムを持つ中間コレクションを作成したくありません。

それでも意味が分からない場合は、上記のコード例を検討してください。 が呼び出されるget_items列挙を返します。select渡されるselectのは、必要なときにいつでもシーケンス内の次のアイテムを提供する方法を知っているインスタンスです。重要なのは、アイテムのコレクション全体がまだ計算されていないことです。selectアイテムが必要な場合にのみ、アイテムを要求し、潜在的なコードget_itemsが動作して提供します。この怠惰はチェーンに沿って運ばれ、要求されたselectときにのみシーケンスから次のアイテムを描画します。mapそのため、一度に 1 つのデータ項目に対して長い一連の操作を実行できます。実際、このように構造化されたコードは、無限のプロセスを処理することさえできます。メモリエラーのない一連の値。

したがって、この種の怠惰は C# で簡単にコーディングできますが、Ruby でそれを行う方法がわかりません。

それがより明確であることを願っています (今後は午前 3 時に質問を書かないようにします。)

4

4 に答える 4