tags:

views:

1248

answers:

4

How do I transform this IEnumerable<KeyValuePair<MyType, IEnumerable<OtherType>>> into new sequence of the same type, except I just want First() that is in the value (IEnumerable<OtherType>). Something like this (pseudo code):

  var toReturn = from kv in source
                 let k = new KeyValuePair(kv.Key, kv.Value.First())
                 select k;
+4  A: 

I'm unsure if you want the Value in the new KeyValuePair to be an enumerable of that type or a single element. Here's both versions

IEnumerable version

var toReturn = source.Select(x => new KeyValuePair<SomeType,IEnumerable<SomeOtherType>>(x.Key, x.Value.Take(1));

Non-Enumerable Version

var toReturn = source.Select(x => new KeyValuePair<SomeType,SomeOtherType>(x.Key,x.Value.First());
JaredPar
Thanks bunch, I needed first version. I actually tried that but forgot to specify the types in KeyValuePair, and was getting an error.
epitka
+4  A: 

All you're missing is the type of KeyValuePair to use. You could use Jared's lambda expression version, or if you like the query expression syntax:

var toReturn = from kv in source
               select new KeyValuePair<MyType, OtherType>(kv.Key, 
                                                          kv.Value.First());

If you don't want to explicitly specify the type arguments, you could create your own helper class and use type inference:

// Non-generic helper class.
public static class KeyValuePair
{
    public static KeyValuePair<TKey, TValue> Of(TKey key, TValue value)
    {
        return new KeyValuePair<TKey, TValue>(key, value); 
    }
}

at which point your query becomes:

var toReturn = from kv in source
               select KeyValuePair.Of(kv.Key, kv.Value.First());

or

var toReturn = source.Select(kv => KeyValuePair.Of(kv.Key, kv.Value.First());

EDIT: Oops - I think I'd misread your question as well. If you want it to be of the exact same type, i.e. with the value being enumerable too, just use Take(1) instead of First():

var toReturn = source.Select(kv => KeyValuePair.Of(kv.Key, kv.Value.Take(1));

(Isn't type inference lovely? :)

Jon Skeet
I called my "Of" method "Create" instead, but I really love that approach when I need to manually create KeyValuePairs...
Joel Mueller
A: 

Why do you want to get a collection of the same type? When you just have the first element, you don't need a collection (IEnumerable<OtherType>) but a single value (OtherType).

This (like the one you posted) should be correct (you will just need to add generic parameters for the KeyValuePair)

  var toReturn = from kv in source select new KeyValuePair<SomeType, OtherType>(kv.Key, kv.Value.First());

If you really want to get a collection of the same type, write

var toReturn = from kv in source select new KeyValuePair<SomeType, IEnumerable<OtherType>>(kv.Key, new [] { kv.Value.First() });

Note: You don't need to give explicit type arguments to the KeyValuePair when you wrap this into a generic function.

KeyValuePair<TKey, TValue> Pair<TKey, TValue>(TKey key, TValue value) {
    return new KeyValuePair<TKey, TValue>(key, value);
}
//
var foo = Pair(1, "Hello");
Dario
I needed in a same type to be able to pipe it to the same method that handles the other one. This is ordered by date creation desc, and I need to show all or just latest ones.
epitka
+1  A: 
var toReturn = source
.ToDictionary(
  kvp => kvp.Key,
  kvp => kvp.Value.Take(1)
);
David B