24

我正在尝试找到以下代码的 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);

但是我还没有找到一种方法来确定循环在哪个迭代上。任何帮助,将不胜感激!

4

11 回答 11

30

LINQ 没有ForEach方法,这是有充分理由的。LINQ 用于执行查询。它旨在从某些数据源获取信息。它不是为改变数据源而设计的。LINQ 查询不应引起副作用,这正是您在这里所做的。

该类确实有一个方法,这就是您正在使用List的方法。因为它实际上不在命名空间中,所以在技术上它不是 LINQ 的一部分。ForEachSystem.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++;
    }
}
于 2012-10-24T17:21:45.050 回答
19

如果你真的想使用 List.ForEach,很简单:

//[...]
int i=0;
donations.ForEach(x => nvc.Add("item_name_" + i++, x.AccountName);
于 2016-08-05T17:19:33.137 回答
12

这有点令人费解并创建了一个中间集合,但是如何:

donations.Select((x, i) => new {Name = "item_name_" + i, x.AccountName})
    .ToList()
    .ForEach(x=> nvc.Add(x.Name, x.AccountName));

这使用了包含索引的重载Enumerable.Select

我不得不说,这样做并没有什么真正的好处。您使用中间集合创建了更多开销,恕我直言,您失去了原始 for 循环的可读性。

如果您愿意使用foreach循环而不是List.ForEach. 请参阅@wageoghe 的回答(再次强烈推荐)。

于 2012-10-24T17:24:21.597 回答
10

这是一篇旧文章,但谷歌排名很高,所以我认为更通用的方法会更合适。(另外,我倾向于忘记这是如何完成的,这意味着我每次都必须谷歌......)

假设一个整数列表:

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;
});
于 2019-03-06T10:29:09.590 回答
3

捎带@lc的答案。

foreach (var x in donations.Select((d, i) => new {ItemName = "item_name_" + i, AccountName = d.AccountName}))
{
  nvc.Add(x.ItemName, x.AccountName);
}
于 2012-10-24T18:28:22.240 回答
3

您是否有任何理由不使用 aDictionary<string, string>因为您的名称/键似乎是唯一的?这会更快,您可以使用ToDictionary标准查询运算符。

此外,如果您确实希望使用扩展方法(尽管 Servy 说这里的 for 循环是正确的解决方案),那么您可以编写自己的方法 - 请参见此处

于 2012-10-24T17:28:40.450 回答
2

这也可以使用聚合来完成。检查以下示例:

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声明。唯一的缺点是您需要在每次迭代中将索引的值增加一并返回它。

于 2020-01-13T15:04:23.937 回答
0

我喜欢这样做:

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));
于 2018-11-22T10:46:25.183 回答
-1

一个糟糕的解决方案是简单地使用 select 并返回一个无用的值。

items.toList().Select((el, index) =>
{
    el.doStuff();
    return 0;
});
于 2022-02-28T17:32:10.393 回答
-1

我觉得这个解决方案应该已经在这里了,但是...... Linq 有一个Select包含索引的,你可以随时将它打包到一个元组中并迭代。例如:

foreach ((var item, int n) in TheItems.Select((i,n)=>(i,n))) {
    // item is the current item, n is its index
}

或者,如果您愿意:

foreach (var element in TheItems.Select((item,n)=>(item,n))) {
    // element.item is the current item, element.n is its index
}

或者,类似于这个答案,但稍微不那么冗长,但请注意,这将通过调用杀死惰性评估,这会ToList()在调用之前强制枚举整个源ForEach()

TheItems.Select((item,n)=>(item,n)).ToList().ForEach(element => { 
    // element.item is the current item, element.n is its index
});

无论如何,绝对不需要手动计算项目索引。

于 2022-03-05T04:18:49.023 回答
-2

尝试这个 -

donations.ForEach(x =>
         {
             int index = donations.IndexOf(x);
             nvc.Add("item_name_" + index, x.AccountName);
         });
于 2012-10-24T17:26:48.560 回答