views:

202

answers:

6
list vclAsset<FullAsset>
list callsigns<string>

foreach(FullAsset fa in vclAsset)
{
    if (callsigns.contains(fa.asset.callsign))
    {
         //do something
    }

}

Is there a more elegant way to do the above? A FullAsset object contains an Asset object which in turn has a string "Callsign." Each callsign will be unique, so my list callsigns will only have one of each string, and no two FullAsset objects will share an Asset.callsign variable.

In a nutshell I want to pull all the FullAssets that have a certain callsign, but using a foreach seems clumsy (given that the number of FullAssets that could be contained in said list potentially has no upper limit).

+3  A: 

If your keys are unique, you can use a Dictionary or a Hashtable to speed up searching.

If you only want to find a certain item, you can use the List<T>.Find method and supply a predicate.

FullAsset result = vclAsset.Find
     (fa => callsigns.contains(fa.asset.callsign));

or

List<FullAsset> results = vclAsset.FindAll
     (fa => callsigns.contains(fa.asset.callsign));

If you are using .Net 3.5, LINQ Where may be a better solution, as others have stated, since it returns an enumerator (lazy evaluation) vs a full List.

Groo
You can also use the List<T>.FindAll and supply the predicate
Michael Prewecki
Actually I think underneath .FindAll might use a ForEach anyway but it looks neater :-)
Michael Prewecki
Of course, entire Linq does that, but the point is to avoid repeating foreach statements all the time, and focus on the condition (predicate, comparison, etc).
Groo
LINQ to Objects works with IEnumerable. Zero ExpressionTrees involved. No lazy evaluation for you. And in case i'm wrong - welcome to fix! :)
Arnis L.
I wasn't referring to expression trees, but to the fact that `FindAll` works on a fully instantiated list, and returns a full list of elements, while `Where` checks one element at a time, *yield returing* a single result on each iteration. For example, if you have a `break` statement inside your `foreach` loop, it may never access all the elements in your original enumeration. Or if you are using the `Select` statement to project `Where` results, then the difference will be even bigger, since you will only be projecting one item at a time.
Groo
+3  A: 

You could use a lambda expression, something like this:

foreach(FullAsset fa in vclAsset.Where(a => callsigns.contains(a.asset.callsign))
{
    // do something
}
AdaTheDev
+1. you was faster... I have deleted my answers. (it was == your).
Zote
Nicer, but mostly syntactic sugar
Ralph Rickenbach
+2  A: 

Sure, using linq.

var assets=    vclAsset.Where(fullA=>allsigns.contains(fullA.asset.callsign));

assets will be some enumerable structure.

I can recommend 100 Linq samples for inspiration and learning

Henrik Jepsen
+1 - similar to the answer I used syntactically (if only we could accept two!) - is there a difference in performance, or is it purely an aesthetic change?. Many thanks for the linq examples!
MoominTroll
I had already type half of the response when the other answer arrived. I just wanted to add the link which really helped me out when first exploring Linq.
Henrik Jepsen
A: 

Not sure if it counts as more elegant but you can use linq...

        var results = from fa in vclAsset
                      where callsigns.Contains(fa.asset.callsign)
                      select fa;
IanR
A: 
var result = vclAsset.Where(x=>callsigns.Any(y=>x.asset.callsign==y));

P.s. I would rename vclAsset and asset/callsign properties.

Arnis L.
A: 

You can also use the Join function to do this.

var sortedList = vclAsset.Join(callsigns,
    x => x.asset.callsign, x => x,
    x, y => x);

This is the list of vclAssets that have the listed callsign.

Jason