2009-08-19 5 views
6

J'ai deux List<T> objets:Fusionner et mise à jour deux listes en C#

Par exemple:

Liste 1:
ID, valeur où Id est rempli et la valeur est vide et il contient dire ID de 1 à 10.
1 ""
2 ""

... 10 ""

Liste 2:
ID, valeur et autres attributs tous remplis de valeurs mais cette liste est un sous-ensemble de la liste 1 en termes d'ID. (seulement 3 articles par exemple)
2,67
4,90
5,98

Ce que je veux une liste fusionnée 1, mais avec des valeurs mises à jour. Est-ce que quelqu'un a une bonne méthode d'extension qui fera cela ou n'importe quel code élégant pour effectuer cette opération. La liste finale devrait être:

ID, valeur
1 ""
2,67 // valeur de la liste 2
3 ""
4,90
5,98
6, ""
...
10 ""

+0

est votre * Valeur * une chaîne ou un int? Vous semblez montrer des chaînes dans la liste 1 alors que les ints dans la liste 2. – Noldorin

Répondre

3

Je probablement utiliser un dictionnaire plutôt qu'une liste:

// sample data 
    var original = new Dictionary<int, int?>(); 
    for (int i = 1; i <= 10; i++) 
    { 
     original.Add(i, null); 
    } 
    var updated = new Dictionary<int, int>(); 
    updated.Add(2, 67); 
    updated.Add(4, 90); 
    updated.Add(5, 98); 
    updated.Add(11, 20); // add 

    // merge 
    foreach (var pair in updated) 
    { 
     original[pair.Key] = pair.Value; 
    } 

    // show results 
    foreach (var pair in original.OrderBy(x => x.Key)) 
    { 
     Console.WriteLine(pair.Key + ": " + pair.Value); 
    } 

Si vous parlez de propriétés d'un objet, il sera plus délicat, mais toujours faisable.

+0

Merci, c'est ce que je recherchais .... – chugh97

3

Ceci est O (m * n), mais devrait faire le travail pour les listes arbitraires

 foreach (var record in List1) 
     { 
      var other = List2.FirstOrDefault(x => x.Key == record.Key); 
      if(other != null) record.Value = other.Value; 
     } 

Si les listes sont garanties commandées, alors il pourrait être ramené à O (n) au prix de plus de code. Le algortihme serait

Current items start as head of each list 
While items remain in both lists 
    If the current item of list1 has lower key than list2 advance to next in list1 
    else if the current item of list2 has lower key than list1 advance to next in list2 
    else copy value from current list2 item into list1 item and advance both lists. 
0

Si vous avez les deux listes triées par ID, vous pouvez utiliser une variante de l'algorithme de fusion classique:

int pos = 0; 
foreach (var e in list2) { 
    pos = list1.FindIndex(pos, x => x.Id==e.Id); 
    list1[pos].Value = e.Value; 
} 

Notez que cela nécessite aussi list2 être un sous-ensemble strict de list1 en termes d'identité (c.-à-list1 contient vraiment tous ids de list2)

Bien sûr, vous pouvez également envelopper cela dans une méthode d'extension

public static void UpdateWith<T>(this List<T> list1, List<T> list2) 
where T:SomeIdValueSupertype { 
    int pos = 0; 
    foreach (var e in list2) { 
    pos = list1.FindIndex(pos, x => x.Id==e.Id); 
    list1[pos].Value = e.Value; 
    } 
} 
9

utilisez linq: list1 = list2.Union (liste1);

+0

J'ai essayé votre code avec deux listes de type 'liste ' l'étudiant de classe ressemble à ceci 'Student student = new Student() {Id = 1, Name = "foo"} 'En utilisant cette syntaxe' list1 = list2.ToList(). Union (list1.ToList()). ToList(); 'mais elle n'a pas fusionné deux listes; il les a simplement collés ensemble comme un [UNION -voir l'exemple 3] (http://stackoverflow.com/questions/49925/what-is-the-difference-between-union-and-union-all). Êtes-vous sûr qu'il fusionne la liste avec les valeurs mises à jour? – surfmuggle

+0

J'ai trouvé cette question sur la façon de [supprimer les doublons lors de la fusion de listes] (http://stackoverflow.com/questions/16980485/remove-duplicates-while-merging-lists-using-union-in-linq) et cela confirme que Votre code ne fonctionne que si la classe remplace 'GetHashCode()' et 'Equals()' – surfmuggle

0
private void btnSearch_Click(object sender, EventArgs e) 
{ 
String searchBy = cmbSearchBy.Text.ToString(); 
String searchFor = txtSearchFor.Text.Trim(); 

var List3 = (from row in JobTitleDB.jobList 
         where (row.JID.ToString()+row.JobTitleName.ToString().ToLower()).Contains(searchFor.ToLower()) 
         select row).ToList(); 
if (searchBy == "All") 
      { 
       dgJobTitles.DataSource = null; 
       //dgJobTitles.DataSource = List1; 
       //dgJobTitles.DataSource = List2; 
       //dgJobTitles.DataSource = List1.Concat(List2); 
       //dgJobTitles.DataSource = List1.Union(List2); 
       dgJobTitles.DataSource = List3; 
       //dgJobTitles.DataSource=List1.AddRange(List2); 
      } 
} 
+0

Veuillez fournir quelques explications ici. Supprime le code commenté inutile. – BuddhiP

0
Dictionary<int, string> List1 = new Dictionary<int, string>(); 
List1.Add(1,""); 
List1.Add(2,""); 
List1.Add(3,""); 
List1.Add(4,""); 
List1.Add(5,""); 
List1.Add(6,""); 

Dictionary<int, string> List2 = new Dictionary<int, string>(); 
List2.Add(2, "two"); 
List2.Add(4, "four"); 
List2.Add(6, "six"); 

var Result = List1.Select(x => new KeyValuePair<int, string>(x.Key, List2.ContainsKey(x.Key) ? List2[x.Key] : x.Value)).ToList(); 
Questions connexes