Reputation: 61812
I'm trying to find the LINQ equivalent of the following code:
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);
}
I was hoping I could use something like:
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);
But I've not found a way to determine which iteration the loop is on. Any help would be appreciated!
Upvotes: 34
Views: 101749
Reputation: 47
I strongly recommend against this method, unless you're trolling your friends.
This is a way to create a "For" loop with Linq, but with MANY downsides:
int[] arr = new int[] {1, 1, 1, 1};
Enumerable.Range(0, arr.length)
.ToList()
.ForEach(i =>
{
arr[i] += 2;
});
The array should now be {3, 3, 3, 3}
.
Again, do not use this!
Some of these downsides are (but not limited to):
Here's an example of how unreadable it can be:
I made this so my friend wouldn't mess with my code.
The code creates a "for" loop that goes from 0.00 to 1.00 at an 0.01 increment and then "bakes" the curve.
Upvotes: -2
Reputation: 40336
C# 7 (circa 2017) added a cleaner tuple syntax, which can be used with the indexed form of Select
(there's no need to compute the index manually) to give a nice concise syntax. E.g.:
foreach ((var item, int n) in TheItems.Select((i,n)=>(i,n))) {
// item is the current item, n is its index
}
Or if you prefer:
foreach (var element in TheItems.Select((item,n)=>(item,n))) {
// element.item is the current item, element.n is its index
}
So in the OP's case, for example:
foreach ((var item, int n) in donations.Select((i,n)=>(i,n)))
nvc.Add($"item_number{n}", item.AccountName);
Or, if you prefer:
foreach ((var k, var v) in donations.Select((i,n)=>($"item_number_{n}",i.AccountName)))
nvc.Add(k, v);
Or, similar to this answer but slightly less verbose, but note that this will kill lazy evaluation by calling ToList()
, which forces enumeration over the whole source prior to calling ForEach()
:
TheItems.Select((item,n)=>(item,n)).ToList().ForEach(element => {
// element.item is the current item, element.n is its index
});
Upvotes: -2
Reputation: 6278
A crappy solution would be to simply use select and return a useless value.
items.toList().Select((el, index) =>
{
el.doStuff();
return 0;
});
Upvotes: -3
Reputation: 2327
This can be done using aggregate as well. Check the following example:
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
here acts as a for
statement. The only downside is that you need to increase the value of the index by one in each iteration and return it.
Upvotes: 4
Reputation: 227
This is an old post but is highly ranked by Google so I figured a more generic approach would be suitable. (Also, I tend to forget how this is done which means I have to google every time...)
Assume a list of integers:
var values = new List<int>() { 2, 3, 4, 0x100, 74, 0xFFFF, 0x0F0F };
To iterate the list and having an index do the following:
values.Select((x, i) => new
{
item = x,
index = i
})
.ToList()
.ForEach(obj =>
{
int value = obj.item;
int valueIndex = obj.index;
});
Upvotes: 16
Reputation: 157
I like to do that the following way:
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));
Upvotes: 0
Reputation: 116498
It's a little convoluted and creates an intermediate collection, but how about:
donations.Select((x, i) => new {Name = "item_name_" + i, x.AccountName})
.ToList()
.ForEach(x=> nvc.Add(x.Name, x.AccountName));
This uses the overload of Enumerable.Select
which incorporates the index.
I do have to argue there is nothing really to gain from doing it this way. You create more overhead with the intermediate collection and IMHO lose readability over your original for-loop.
You can also skip the intermediate collection if you're willing to use foreach
loop instead of List.ForEach
. See @wageoghe's answer (again highly recommended).
Upvotes: 16
Reputation: 309
If you really want to use a List.ForEach, it's simple:
//[...]
int i=0;
donations.ForEach(x => nvc.Add("item_name_" + i++, x.AccountName);
Upvotes: 30
Reputation: 27608
Piggybacking on the answer by @lc.
foreach (var x in donations.Select((d, i) => new {ItemName = "item_name_" + i, AccountName = d.AccountName}))
{
nvc.Add(x.ItemName, x.AccountName);
}
Upvotes: 4
Reputation: 34349
Is there any reason you're not using a Dictionary<string, string>
as your names/keys appear to be unique? This would be faster and you could use the ToDictionary
standard query operator.
Also, if you did wish to use an extension method (although as Servy says a for loop is the right solution here), then you could write your own - see here.
Upvotes: 3
Reputation: 81253
Try this -
donations.ForEach(x =>
{
int index = donations.IndexOf(x);
nvc.Add("item_name_" + index, x.AccountName);
});
Upvotes: -1
Reputation: 203834
LINQ doesn't have a ForEach
method, and for good reason. LINQ is for performing queries. It is designed to get information from some data source. It is not designed to mutate data sources. LINQ queries shouldn't cause side effects, which is exactly what you're doing here.
The List
class does have a ForEach
method, which is what you are using. Because it's not actually in the System.Linq
namespace it's not technically a part of LINQ.
There is nothing wrong with the for
loop in your question. It would be wrong (from a good practice perspective) to try to change it in the way that you're trying to.
Here is a link that discusses the matter in more detail.
Now, if you want to ignore that advice and use a ForEach
method anyway, it's not hard to write one that provides an index to the action:
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++;
}
}
Upvotes: 40