2009-08-19 7 views
6

Ho due List<T> oggetti:Unisci e aggiornare due liste in C#

Per esempio:

Lista 1:
ID, valore dove ID è popolato e valore è vuoto e contiene dire gli ID da 1 a 10.
1 ""
2 ""
...
10 ""

Elenco 2:
ID, Valore e altri attributi tutti riempiti con valori ma questa lista è un sottoinsieme dell'elenco 1 in termini di ID. (per esempio solo 3 articoli)
2,67
4,90
5,98

Quello che voglio è una lista unito 1, ma con valori aggiornati. Qualcuno ha un buon metodo di estensione che farà questo o qualsiasi codice elegent per eseguire questa operazione. La lista finale dovrebbe essere:

ID, valore
1 ""
2,67 // valore dalla lista 2
3 ""
4,90
5,98
6, ""
...
10 ""

+0

la tua * Valore * una stringa o un int? Sembra che tu mostri le stringhe nella lista 1 rispetto a quelle dell'elenco 2. – Noldorin

risposta

3

Io probabilmente utilizzare un dizionario piuttosto che un elenco:

// 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); 
    } 

Se si sta parlando di proprietà di un oggetto, sarà più complicato, ma ancora fattibile.

+0

Grazie, questo è quello che stavo provando .... – chugh97

3

Questo è O (m * n), ma dovrebbe fare il lavoro per gli elenchi arbitrari

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

Se gli elenchi sono garantiti ordinati, quindi potrebbe essere portato a O (n) al costo di più codice. L'algoritmo desiderato sarebbe

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

Se hai entrambi gli elenchi ordinati per ID, è possibile utilizzare una variante dell'algoritmo merge classica:

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

Si noti che questo richiede anche list2 di essere un sottoinsieme rigoroso di list1 in termini di ID (vale a dire list1 contiene davvero tutti iD di list2)

Naturalmente si possono anche avvolgere questo in un metodo di estensione

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

usare linq: lista1 = lista2.Union (list1);

+0

Ho provato il tuo codice con due elenchi di tipo 'lista ' lo studente di classe assomiglia a questo 'Student student = new Student() {Id = 1, Name = "pippo"} 'Usando questa sintassi' list1 = list2.ToList(). Union (list1.ToList()). ToList(); 'ma non unire il due liste; li ha semplicemente incollati insieme come [UNION - vedi esempio 3] (http://stackoverflow.com/questions/49925/what-is-the-difference-between-union-and-union-all). Sei sicuro che 'unisca l'elenco con i valori aggiornati? – surfmuggle

+0

Ho trovato questa domanda su come [rimuovere i duplicati durante la fusione degli elenchi] (http://stackoverflow.com/questions/16980485/remove-duplicates-while-merging-lists-using-union-in-linq) e conferma che il tuo codice funziona solo se la classe sovrascrive 'GetHashCode()' e '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

Fornisci qualche spiegazione qui. Rimuovi il codice commentato non necessario. – 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();