tags:

views:

51

answers:

2

I have 2 sequences, each of which returns an anonymous type with 2 fields (call them x and y). Semantically, x serves as a key and y a value in both of these sequences.

How can I specify that the first sequence has precedence over the second in case the same x appears in both, and thus merge them into 1 sequence?

A: 

You might find it easier to do it without Linq, but I'm thinking something like this:

var distinctWithPrecedence = seq1
  .Concat(seq2)
  .GroupBy(i => i.x)
  .Select(g => g.First());

If Linq doesn't do to much under the covers. The basic idea is group by the key. Then go through the groupings pulling the first element from each. If Linq behaves how I think it should the first element will be the first one from the concatenated list, meaning the first sequence has precedent.

There's probably other ways to do it, but this is the first that came to mind.

Talljoe
A: 

I would start with

var res = seq1.Union(seq2, Comparer);

but the documentation for Enumerable.Union doesn't specify from which sequence a matching element is taken, and requires Comparer to be an implementation of IEqualityComparer<TSource> which you won't have if TSource is an anonymous type (but might be worth making concrete to allow this).

Otherwise you would need to implement you own helper, something like:

IEnumerable<KeyValuePair<TKey, TValue>> Union(
                     this IEnumerable<KeyValuePair<TKey, TValue>> first,
                     IEnumerable<KeyValuePair<TKey, TValue>> second) {
   var allFirst = first.ToDictionary(v => v.Key, v => v.Value);
   foreach (var kv in allFirst) { yield return kv; }

   foreach (var s in second) {
     if (!allFirst.ContainsKey(s.Key)) {
       yield return s;
     }
 }

(If you want to stick with your own type (properties x & y), you can make this generic over a single type parameter, but you will need to add a type constraint to give access to the separate properties.)

Richard