Reputation: 1944
I have the following code in one of my methods:
foreach (var s in vars)
{
foreach (var type in statusList)
{
if (type.Id == s)
{
Add(new NameValuePair(type.Id, type.Text));
break;
}
}
}
This seems sort of ineffective to me, and I was wondering if there was a way to substitute at least one of the foreaches wih a LINQ query. Any suggestions?
EDIT: vars is an array of strings and the Add method adds an item to a CSLA NameValueList.
Upvotes: 3
Views: 24487
Reputation: 110071
I don't see an answer with a group join, so here's one:
var result = vars
.GroupJoin
(
statusList,
s => s,
type => type.Id,
(s, g) => g.Any() ? g.First() : null
)
.Where(type => type != null)
.Select(type => new NameValuePair(type.Id, type.Text));
Upvotes: 1
Reputation: 1500055
EDIT: I hadn't noticed the break;
before
If there could be more than one type with the relevant ID, then you need to use FirstOrDefault
as per Keith's answer or my second code sample below.
EDIT: Removing "multi-from" version as it's unnecessarily inefficient assuming equality/hashcode works for whatever the type of type.Id
is.
A join is probably more appropriate though:
var query = from s in vars
join type in statusList on s equals type.Id
select new NameValuePair(type.Id, type.Text);
foreach (var pair in query)
{
Add(pair);
}
You might want to make an AddRange
method which takes an IEnumerable<NameValuePair>
at which point you could just call AddRange(query)
.
Alternatively, you can use a LookUp. This version makes sure it only adds one type per "s".
var lookup = types.ToLookup(type => type.Id);
foreach (var s in vars)
{
var types = lookup[s];
if (types != null)
{
var type = types.First(); // Guaranteed to be at least one entry
Add(new NameValuePair(type.Id, type.Text));
}
}
The benefit of this is that it only goes through the list of types once to build up a dictionary, basically.
Upvotes: 6
Reputation: 421978
Something like this:
foreach(var s in vars) {
var type = statusList.FirstOrDefault(t => t.Id == s);
if (type != null)
Add(new NameValuePair(type.Id, type.Text));
}
Or if vars supports ForEach
method, this would work too (however I recommend against overLINQifying):
vars.ForEach(s => {
var type = statusList.FirstOrDefault(t => t.Id == s);
if (type != null)
Add(new NameValuePair(type.Id, type.Text));
});
I assumed type
is an instance of a reference type.
Upvotes: 2
Reputation: 27055
If your Add method is constructing a list, you might also try:
IEnumarable<NamedValuePair> result = statusList.Where(type => type.Id == s).Select(new NameValuePair(type => type.Id, type.Text));
Upvotes: 2
Reputation: 14956
Bart de Smet has an implementation of an extension ForEach for IEnumerable.
Upvotes: 1
Reputation: 155652
Basically:
var types =
from s in vars
let type = (
from tp in statusList
where tp.Id == s ).FirstOrDefault()
where type != null
select new NameValuePair(type.Id, type.Text)
Upvotes: 12