アクセスの列挙子内foreachループ?
-
11-09-2019 - |
質問
いリストクラスは、どのようなオーバーライド GetEnumerator()
戻り、自分の列挙子クラスです。この列挙子のクラスが追加物件のように更新され、列挙子を使用します。
簡単のため(こうではない正確な業務の場合)、これらの特性 CurrentIndex
や RunningTotal
.
私の管理これらの特性にforeachループの手がされているのではないかと思い封止この機能を再利用の列挙子が右ます。
の問題: foreach 隠のすべての列挙子事業ですが、foreach文のアクセスの現在の調査員はその取得自。やしていますforeachを使用し手なループ、操作の列挙子ん。
解決
厳密に私はあなたが言っている正確に何をしたい場合は、[はい、あなたはGetEnumeratorメソッドを呼び出すと、whileループで列挙子を自分でコントロールする必要があるだろうと言うでしょう、話してます。
あなたのビジネス要件についてはあまり知らない、あなたは、このようなこのようなものとして、イテレータの機能を利用することができるかもしれない。
public static IEnumerable<decimal> IgnoreSmallValues(List<decimal> list)
{
decimal runningTotal = 0M;
foreach (decimal value in list)
{
// if the value is less than 1% of the running total, then ignore it
if (runningTotal == 0M || value >= 0.01M * runningTotal)
{
runningTotal += value;
yield return value;
}
}
}
次に、あなたがこれを行うことができます:
List<decimal> payments = new List<decimal>() {
123.45M,
234.56M,
.01M,
345.67M,
1.23M,
456.78M
};
foreach (decimal largePayment in IgnoreSmallValues(payments))
{
// handle the large payments so that I can divert all the small payments to my own bank account. Mwahaha!
}
<時間>
更新:
[OK]を、ので、ここで私は「釣り針」ソリューションと名付けたものとフォローアップです。さて、私は私は本当に何かをする十分な理由この方法を考えることはできません免責事項を追加してみましょうが、あなたの状況が異なる場合があります。
アイデアは、あなたは、単にあなたのイテレータ関数に渡す「釣りフック」オブジェクト(参照型)を作成することです。イテレータ関数は、あなたの釣りフックオブジェクトを操作して、あなたはまだ外で、あなたのコード内で、それへの参照を持っているので、あなたは何が起こっているかを可視化しています:
public class FishingHook
{
public int Index { get; set; }
public decimal RunningTotal { get; set; }
public Func<decimal, bool> Criteria { get; set; }
}
public static IEnumerable<decimal> FishingHookIteration(IEnumerable<decimal> list, FishingHook hook)
{
hook.Index = 0;
hook.RunningTotal = 0;
foreach(decimal value in list)
{
// the hook object may define a Criteria delegate that
// determines whether to skip the current value
if (hook.Criteria == null || hook.Criteria(value))
{
hook.RunningTotal += value;
yield return value;
hook.Index++;
}
}
}
あなたはこのようにそれを利用することになります
List<decimal> payments = new List<decimal>() {
123.45M,
.01M,
345.67M,
234.56M,
1.23M,
456.78M
};
FishingHook hook = new FishingHook();
decimal min = 0;
hook.Criteria = x => x > min; // exclude any values that are less than/equal to the defined minimum
foreach (decimal value in FishingHookIteration(payments, hook))
{
// update the minimum
if (value > min) min = value;
Console.WriteLine("Index: {0}, Value: {1}, Running Total: {2}", hook.Index, value, hook.RunningTotal);
}
// Resultint output is:
//Index: 0, Value: 123.45, Running Total: 123.45
//Index: 1, Value: 345.67, Running Total: 469.12
//Index: 2, Value: 456.78, Running Total: 925.90
// we've skipped the values .01, 234.56, and 1.23
基本的に、FishingHookオブジェクトは、あなたのイテレータがどのように実行するかをある程度制御することができます。私は質問から得た印象は、あなたが反復処理の途中である一方で、それは反復処理方法を操作することができるようにイテレータの内部の仕組みにアクセスするためのいくつかの方法が必要であることだったが、これはそうではありません場合は、このソリューションは、かもしれませんあなたが必要なもののためにやり過ぎています。
他のヒント
foreach
を使用すると、確かに列挙子を取得することはできません - あなたは、しかし、列挙子リターン(yield
)のタプルを持つことができますは、そのデータを含んでいます。実際には、あなたはおそらくあなたのためにそれを行うためにLINQを使用することができます...
(私はをきれいにのLINQを使用してインデックスを取得できませんでした - しかし、Aggregate
を経由して合計し、現在の値を取得することができます。ので、ここでタプルアプローチがあります)。
using System.Collections;
using System.Collections.Generic;
using System;
class MyTuple
{
public int Value {get;private set;}
public int Index { get; private set; }
public int RunningTotal { get; private set; }
public MyTuple(int value, int index, int runningTotal)
{
Value = value; Index = index; RunningTotal = runningTotal;
}
static IEnumerable<MyTuple> SomeMethod(IEnumerable<int> data)
{
int index = 0, total = 0;
foreach (int value in data)
{
yield return new MyTuple(value, index++,
total = total + value);
}
}
static void Main()
{
int[] data = { 1, 2, 3 };
foreach (var tuple in SomeMethod(data))
{
Console.WriteLine("{0}: {1} ; {2}", tuple.Index,
tuple.Value, tuple.RunningTotal);
}
}
}
こともできないようなことがより機能によっては、購入できます。何かできるものとして"zipping"と複数の配列を繰り返し処理します。のシーケンスの例でやりくりは夫婦で別にされています:
- の価値配列
- のインデックスが配列
- の"中間合計"配列
次のステップが指定はそれぞれの配列を別途:
List<decimal> ValueList
var Indexes = Enumerable.Range(0, ValueList.Count)
最後の一つであるトーベ-ヤンソンは、フィ...のかを考えることができるはずして使う一時的な変数を配列、または音楽はグラミー賞にノミネーの和のための各項目を設定します。第二は明らかに少ないperformant,されているのではないかと思いは、一時:
decimal Sum = 0;
var RunningTotals = ValueList.Select(v => Sum = Sum + v);
最後のステップにするzipこととなります。.純4の Zipオペレーター内蔵, ると次のようになります:
var ZippedSequence = ValueList.Zip(Indexes, (value, index) => new {value, index}).Zip(RunningTotals, (temp, total) => new {temp.value, temp.index, total});
この明らかにしnoisierのから、いろいろなものが入ってるんzip。
のリンクが、ソースコードの実施のためのウェブサイトの機能ます。になっているので簡単に少しのコードです。