2012-04-11 38 views
5

ho due dizionari ordinati sia con la firma di tipozippare/fusione di due liste ordinate

cioè

SortedDictionary<decimal, long> A 
SortedDictionary<decimal, long> B 

voglio unire le due liste in cui la chiave è lo stesso, creando così una nuova lista come

SortedDictionary<decimal, KeyValuePair<long,long>> 
or 
SortedDictionary<decimal, List<long>> 

questo potrebbe non essere il modo migliore di approacing la situazione, ma qualcuno potrebbe darmi un testa a testa su come fare questo o un modo migliore per avvicinarsi.

+0

Perché secondo KeyValuePair? Non è solo una lista ? La lista – Tigran

+0

funzionerebbe pure. aggiunto in – Abstract

+3

Cercando di essere sicuro di capire cosa stai cercando - vuoi che gli elementi presenti solo * uno * dei dizionari iniziali appaiano nel dizionario di output, o * solo * i tasti che appaiono in entrambi i dizionari? @Tigran - spero che questo chiarisca le cose –

risposta

5

Questo è quello che ho:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>> 
(
    A.Union(B) 
    .ToLookup(x => x.Key, x => x.Value) 
    .ToDictionary(x => x.Key, x => new List<long>(x)) 
); 

EDIT: Sopra soluzione seleziona chiavi non inclusi in entrambe le collezioni. Questo dovrebbe selezionare in cui le chiavi sono gli stessi:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>> 
(
    A.Where(x=>B.ContainsKey(x.Key)) 
    .ToDictionary(x => x.Key, x => new List<long>(){x.Value, B[x.Key]}) 
); 
+0

oooo Penso che questo sia un modo abbastanza pulito di avvicinarsi! Mi piace il .ToLookup() chiamare meglio di un GroupBy - rende più facile la comprensione penso –

+0

OP dovrebbe guardare oltre per la risposta :) – NSGaga

+0

"Voglio unire le due liste in cui la chiave è lo stesso." La tua risposta include chiavi che non sono in entrambi i dizionari. – jason

0

Un altro modo LINQ di fare questo che penso che cattura l'intento migliore in termini di operazioni di set:

SortedDictionary<decimal, long> a = new SortedDictionary<decimal, long>(); 
SortedDictionary<decimal, long> b = new SortedDictionary<decimal, long>(); 

a.Add(0, 10); 
a.Add(1, 10); 
a.Add(2, 100); 
a.Add(100, 1); 

b.Add(0, 4); 
b.Add(4, 4); 
b.Add(2, 10); 

var result = a.Union(b) 
    .GroupBy(x => x.Key) 
    .ToDictionary(x => x.Key, x => x.Select(y => (long)y.Value).ToList()); 
+0

Questo non aggiungerebbe elementi che non hanno la stessa ** chiave ** in entrambi i dizionari. – Tigran

+0

nota che non so se c'è un requisito per l'output di essere un "SortedDictionary". Se è così, non è difficile rimediare. –

+0

@Tigran - l'OP ha dichiarato 'Voglio unire le due liste in cui la chiave è la stessa'. Ho preso a significare un'Unione –

0

provare qualcosa di simile, ma non è facile:

Dictionary<decimal, long> dic1 = new Dictionary<decimal, long>{ {3,23}, {2,3}, {5,4}, {6,8}}; 
    Dictionary<decimal, long> dic2 = new Dictionary<decimal, long>{ {3,2}, {2,5}, {5,14}, {12,2}}; 


    //recover shared keys (the keys that are present in both dictionaries) 
    var sharedKeys = dic1.Select(dic => dic.Key).Intersect(dic2.Select(d2=>d2.Key)); 
    sharedKeys.Dump(); 

    //add to the fìnal dictionary 
    var final = new Dictionary<decimal, List<long>>(); 
    foreach(var shk in sharedKeys) { 

     if(!final.ContainsKey(shk)) 
      final[shk] = new List<long>(); 

     final[shk].Add(dic1[shk]); 
     final[shk].Add(dic2[shk]); 
    } 

**EDIT** 
//Skip below part if you need only keys present on both dictionaries. 
///----------------------------------------------------------------- 

    //get unique keys present in Dic1 and add 
    var nonsharedkeys1 = dic1.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k)); 
    foreach(var nshk in nonsharedkeys1) { 

     final[nshk] = new List<long>();    
     final[nshk].Add(dic1[nshk]);   
    } 

    //get unique keys present in Dic2 and add 
    var nonsharedkeys2 = dic2.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k)); 
    foreach(var nshk in nonsharedkeys2) { 

     final[nshk] = new List<long>();    
     final[nshk].Add(dic2[nshk]);   
    } 

Dovrebbe lavoro per te.

0

Si può fare questo semplicemente usando LINQ:

var query = from a in A 
      join b in B 
       on a.Key equals b.Key 
      select new { 
       Key = a.Key, 
       Value = Tuple.Create(a.Value, b.Value) 
      }; 
var merged = new SortedDictionary<decimal, Tuple<long, long>>(
       query.ToDictionary(x => x.Key, x => x.Value) 
      ); 

Penso che si dovrebbe usare Tuple<long, long> come TValue nel dizionario unito.

+0

i risultati sono diversi da quelli che ho ottenuto con la sintassi dell'estensione quando vengono eseguiti con gli stessi dati. Il tuo produce: {{0, {10, 4}, {2, {100, 10}}}. Il mio produce: {{0, {10,4}}, {1, {10}}, {2, {100,10}}, {100, {1}}, {4, {4}}} (usando voci di esempio nel mio post) –

+0

non avrebbe funzionato per 'list1: {{1,1} {2,2}}' e 'lista2: {{2,2} {3,3}}' –

+0

@LB: Noi stanno chiaramente capendo i requisiti in modo diverso. Nel tuo esempio, il mio produce '{2, (2, 2)}'. Ciò sembra coerente con il requisito "Voglio unire le due liste in cui la chiave è la stessa". Per favore dimmi come lo stai capendo. Solo uno di noi può aver ragione. – jason

0

Si potrebbe "abuso" Concat e Aggregate come questo:

var A = new SortedDictionary<decimal,long>(); 
var B = new SortedDictionary<decimal,long>(); 

A.Add(1, 11); 
A.Add(2, 22); 
A.Add(3, 33); 

B.Add(2, 222); 
B.Add(3, 333); 
B.Add(4, 444); 

var C = A.Concat(B).Aggregate(
    new SortedDictionary<decimal, List<long>>(), 
    (result, pair) => { 
     List<long> val; 
     if (result.TryGetValue(pair.Key, out val)) 
      val.Add(pair.Value); 
     else 
      result.Add(pair.Key, new[] { pair.Value }.ToList()); 
     return result; 
    } 
); 

foreach (var x in C) 
    Console.WriteLine(
     string.Format(
      "{0}:\t{1}", 
      x.Key, 
      string.Join(", ", x.Value) 
     ) 
    ); 

L'output risultante:

1:  11 
2:  22, 222 
3:  33, 333 
4:  444 

Questo è più o meno lo stesso come se hai scritto un "normale" foreach e sarebbe di fatto funziona su qualsiasi IEnumerable<KeyValuePair<decimal, long>> (non solo su SortedDictionary<decimal, long>) ed è facile estenderlo a più di due raccolte di input, se necessario.

Sfortunatamente, ignora completamente anche il fatto che l'input SortedDictionary è, beh, ordinato, quindi le prestazioni non sono ottimali. Per prestazioni ottimali dovresti armeggiare con avanzamento lineare separato IEnumerator per ciascuno dei dizionari ordinati di input, mentre confrontando costantemente gli elementi sottostanti - potresti evitare completamente TryGetValue in questo modo ...