次のコードに相当するLINQを見つけようとしています。
NameValueCollection nvc = new NameValueCollection();
List<BusinessLogic.Donation> donations = new List<BusinessLogic.Donation>();
donations.Add(new BusinessLogic.Donation(0, "", "", "");
donations.Add(new BusinessLogic.Donation(0, "", "", "");
donations.Add(new BusinessLogic.Donation(0, "", "", "");
for(var i = 0; i < donations.Count(); i++)
{
// NOTE: item_number_ + i - I need to be able to do this
nvc.Add("item_number_" + i, donations[i].AccountName);
}
私は次のようなものを使用できることを望んでいました:
NameValueCollection nvc = new NameValueCollection();
List<BusinessLogic.Donation> donations = new List<BusinessLogic.Donation>();
donations.Add(new BusinessLogic.Donation(0, "", "", "");
donations.Add(new BusinessLogic.Donation(0, "", "", "");
donations.Add(new BusinessLogic.Donation(0, "", "", "");
donations.ForEach(x => nvc.Add("item_name_" + ??, x.AccountName);
しかし、ループがどのイテレーションにあるかを判別する方法が見つかりませんでした。どんな助けもいただければ幸いです!
LINQにはForEach
メソッドがありません。これには正当な理由があります。 LINQはクエリを実行するためのものです。一部のデータソースから情報を取得するように設計されています。データソースを変更するように設計されているのではありません。 LINQクエリによって副作用が発生することはありません。これがまさにここで行っていることです。
List
クラスdoesには、使用しているForEach
メソッドがあります。実際にはSystem.Linq
名前空間は技術的にはLINQの一部ではありません。
質問のfor
ループに問題はありません。あなたがしようとしている方法でそれを変更しようとすることは(良い習慣の観点から)間違っているでしょう。
ここ は、問題をより詳細に説明するリンクです。
さて、そのアドバイスを無視してForEach
メソッドを使用したい場合は、アクションのインデックスを提供するメソッドを書くのは難しくありません。
public static void ForEach<T>(this IEnumerable<T> sequence, Action<int, T> action)
{
// argument null checking omitted
int i = 0;
foreach (T item in sequence)
{
action(i, item);
i++;
}
}
あなたが本当にList.ForEachを使いたいなら、それは簡単です:
//[...]
int i=0;
donations.ForEach(x => nvc.Add("item_name_" + i++, x.AccountName);
それは少し複雑で中間的なコレクションを作成しますが、どうですか:
donations.Select((x, i) => new {Name = "item_name_" + i, x.AccountName})
.ToList()
.ForEach(x=> nvc.Add(x.Name, x.AccountName));
これは インデックスを組み込んだEnumerable.Select
のオーバーロード を使用します。
私はこの方法でそれを行うことから本当に得るものは何もないと主張する必要があります。中間コレクションを使用するとオーバーヘッドが増え、IMHOは元のforループよりも読みにくくなります。
List.ForEach
の代わりにforeach
ループを使用する場合は、中間コレクションをスキップすることもできます。 @ wageoghe's answer を参照してください(これも強くお勧めします)。
名前/キーが一意であるように見えるため、Dictionary<string, string>
を使用しない理由はありますか?これはより高速で、ToDictionary
標準クエリ演算子を使用できます。
また、拡張メソッドを使用したい場合(Servyはforループがここでの適切なソリューションであると言いますが)、独自に記述することもできます ここ を参照してください。
これは古い投稿ですが、Googleによって高度にランク付けされているため、より一般的なアプローチが適していると考えました。 (また、これがどのように行われるかを忘れがちです。つまり、毎回グーグルする必要があります...)
整数のリストを想定します。
var values = new List<int>() { 2, 3, 4, 0x100, 74, 0xFFFF, 0x0F0F };
リストを反復してインデックスを作成するには、次の手順を実行します。
values.Select((x, i) => new
{
item = x,
index = i
})
.ToList()
.ForEach(obj =>
{
int value = obj.item;
int valueIndex = obj.index;
});
@lcによる回答の便乗。
foreach (var x in donations.Select((d, i) => new {ItemName = "item_name_" + i, AccountName = d.AccountName}))
{
nvc.Add(x.ItemName, x.AccountName);
}
私はそれを次のようにしたいです:
NameValueCollection nvc = new NameValueCollection();
List<BusinessLogic.Donation> donations = new List<BusinessLogic.Donation>();
donations.Add(new BusinessLogic.Donation(0, "", "", ""));
donations.Add(new BusinessLogic.Donation(0, "", "", ""));
donations.Add(new BusinessLogic.Donation(0, "", "", ""));
Enumerable
.Range(0, donations.Count())
.ToList()
.ForEach(i => nvc.Add("item_number_" + i, donations[i].AccountName));
これは、集約を使用して行うこともできます。次の例を確認してください。
var data = new[]
{
"A",
"B",
"C",
"D"
};
var count = data.Aggregate(0, (index, item) =>
{
Console.WriteLine("[{0}] => '{1}'", index, item);
return index + 1;
});
Console.WriteLine("Total items: {0}", count);
Aggregate
ここでは、for
ステートメントとして機能します。唯一の欠点は、反復ごとにインデックスの値を1ずつ増やして返す必要があることです。