views:

99

answers:

5

Is there any other way to get List<foo> directly from ValueCollection.

Current I am using below code

 Dictionary<string,List<foo>> dic;

 List<foo> list= new List<foo>();

 foreach (List<foo> var in dic.Values)
 {               
      list.AddRange(var);
 }  

OR

List<List<foo>> list= new List<List<foo>>(dic.Values);

Above conversion gives me List<List<foo> but I want List<foo> from dic.values without using for each loop if possible using .NET 2.0.

+1  A: 

EDIT: the easy LINQ solution (not available in .NET 2.0)

dic.Values.SelectMany(list => list).ToList()

If you don't need a List and are OK with an IEnumerable then leave off the ToList()

The harder solution:

  1. Define a class which implements IList and which has a constructor which takes a ValueCollection or ICollection
  2. Implement all the methods on that. you can keep track of all the list of T's and the index of the current list you are working on.

use

return new MyListCombiner<foo>(dict.Values);
tster
The OP specifically mentions .NET 2.0.
Ani
OP said "if possible".
Don Kirkby
@Don Kirby: Title says C# 2.0. Never mind, I don't mean to nitpick.
Ani
@Don Kirkby, I read "if possible" as referring to the use of a foreach loop, but it isn't completely clear.
adrift
I think you're right, @adrift, I probably misinterpreted that.
Don Kirkby
+1  A: 

Your foreach loop should be

Dictionary<string,List<foo>> dic;

 List<foo> list= new List<foo>();

 foreach (List<foo> var in dic.Values)
 {    
      foreach(foo bar in var){           
          list.AddRange(bar);
      }
 }  

You were adding each list to a list, when you wanted to be adding each item of each list to a list.

And totally missed the for each loop part in your question.

I don't think that's possible in C# 2.0. LINQ is at heart just doing iterations over an IEnumerable which is all the foreach is doing

msarchet
According to this reference http://msdn.microsoft.com/en-us/library/z883w3dc.aspx `AddRange` adds elements of a collection passed to it as `IEnumerable<T>`, to the list, so the OP's code is correct
Maciej Hehl
@Maciej Hehl this is true, now I want to play with this to see why it isn't doing what it should be.
msarchet
A: 

Ultimately, any method you choose is going to involve a for-loop at some level of abstraction. If you're staying in pure .NET 2.0, you'll have to write that for loop somewhere in your code. This sort of data conglomeration is one of the main purposes of LINQ. See the SelectMany method:

http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany.aspx

Depending on your requirements, you may be able to link to .NET 3.0/3.5, yet still compile on an older version of the toolset. You'd still have to have 3.0/3.5 on the box you are running the application on, but wouldn't have to upgrade your tools. The syntax also wouldn't look as sexy, because you would have to access extension methods via static method syntax.

Merlyn Morgan-Graham
+2  A: 

Without using LINQ or .NET 3.5, I don't know of any way to do this without some kind of for loop. Even with LINQ, somewhere in the framework a foreach would be doing the same thing.

If you're chained to .NET 2.0 but have access to a later C# compiler version, you can use LinqBridge.dll to achieve the same effects - read about it here. Note that this would require at least VS 2008 (targeting the 2.0 framework). If you can use that, then all you'd have to do is

using System.Linq;

...

dic.Values.SelectMany(v => v).ToList();
Ben
LINQ would at least push the foreach out to iteration time instead of creation time.
tster
True - and I suspect that the real win is that OP wouldn't have to write it themselves! With LinqBridge, it would be possible with the 2.0 Framework, too.
Ben
A: 

In C# 2.0 you must use either a loop, or Poor Man's LINQ, with code that looks like this:

Linq(dic.Values).SelectMany(delegate(List<foo> list) { return list; }).ToList()

Where you define Linq() as

static PoorMansLinq<T> Linq<T>(IEnumerable<T> source)
{
    return new PoorMansLinq<T>(source);
}

I noticed that the first line doesn't currently work and I submitted an update to fix it. In the meantime, you can use the following as a workaround:

Linq(Linq(dic.Values).SelectMany(delegate(List<foo> list) { return list; })).ToList()

You could also use LinqBridge, and call Enumerable directly, but this is cumbersome without C# 3.0.

Qwertie