Mam następującą sytuację
class Person
{
string Name;
int Value;
int Change;
}
List<Person> list1;
List<Person> list2;
Muszę połączyć 2 listy w nową List<Person>
w przypadku, gdy jest to ta sama osoba, rekord łączenia miałby to imię, wartość osoby na liście2, zmiana byłaby wartością list2 - wartość list1. Zmiana wynosi 0, jeśli nie ma duplikatu
Odpowiedzi:
Można to łatwo zrobić za pomocą metody rozszerzenia Linq Union. Na przykład:
Spowoduje to zwrócenie listy, w której dwie listy zostaną scalone, a podwójne zostaną usunięte. Jeśli nie określisz elementu porównującego w metodzie rozszerzenia Union, jak w moim przykładzie, użyje ona domyślnych metod Equals i GetHashCode w Twojej klasie Person. Jeśli na przykład chcesz porównać osoby, porównując ich właściwość Name, musisz zastąpić te metody, aby samodzielnie wykonać porównanie. Sprawdź poniższy przykład kodu, aby to osiągnąć. Musisz dodać ten kod do swojej klasy Person.
Jeśli nie chcesz ustawiać domyślnej metody Equals klasy Person, aby zawsze używać Name do porównywania dwóch obiektów, możesz również napisać klasę porównującą, która używa interfejsu IEqualityComparer. Następnie można podać tę funkcję porównującą jako drugi parametr w metodzie Union rozszerzenia Linq. Więcej informacji o tym, jak napisać taką metodę porównującą, można znaleźć pod adresem http://msdn.microsoft.com/en-us/library/system.collections.iequalitycomparer.aspx
źródło
Union
sięIntersect
?Concat
że nie łączy duplikatówZauważyłem, że to pytanie nie zostało oznaczone jako udzielone po 2 latach - myślę, że najbliższa odpowiedź to Richards, ale można to bardzo uprościć:
Chociaż nie będzie to błąd w przypadku, gdy masz zduplikowane nazwy w jednym z zestawów.
Niektóre inne odpowiedzi sugerują użycie łączenia - zdecydowanie nie jest to właściwe rozwiązanie, ponieważ da ci to tylko odrębną listę, bez wykonywania łączenia.
źródło
Dlaczego po prostu nie używasz
Concat
?Concat jest częścią linq i jest bardziej wydajny niż robienie
AddRange()
w Twoim przypadku:
źródło
Actually, due to deferred execution, using Concat would likely be faster because it avoids object allocation - Concat doesn't copy anything, it just creates links between the lists so when enumerating and you reach the end of one it transparently takes you to the start of the next!
To jest mój punkt widzenia.To jest Linq
To jest normalne (AddRange)
To jest normalne (dla każdego)
To jest normalne (Foreach-Dublice)
źródło
Jest na to kilka sposobów, zakładając, że każda lista nie zawiera duplikatów, nazwa jest unikalnym identyfikatorem i żadna z list nie jest uporządkowana.
Najpierw utwórz metodę rozszerzenia dołączania, aby uzyskać jedną listę:
W ten sposób można uzyskać jedną listę:
Następnie grupuj według nazwy
Następnie możesz przetwarzać każdą grupę z pomocą pomocnika, aby przetwarzać jedną grupę na raz
Które można zastosować do każdego elementu
grouped
:(Ostrzeżenie: nieprzetestowane.)
źródło
Append
jest prawie dokładnym duplikatem gotowego do użyciaConcat
.Enumerable.Concat
i dlatego wdrażałem go ponownie.Potrzebujesz czegoś takiego jak pełne połączenie zewnętrzne. System.Linq.Enumerable nie ma metody implementującej pełne sprzężenie zewnętrzne, więc musimy to zrobić sami.
źródło
Czy poniższy kod działa w przypadku Twojego problemu? Użyłem foreach z odrobiną linq w środku do łączenia list i założyłem, że ludzie są równi, jeśli ich imiona pasują, i wydaje się, że po uruchomieniu wypisuje oczekiwane wartości. Resharper nie oferuje żadnych sugestii dotyczących konwersji foreach na linq, więc prawdopodobnie jest to tak dobre, jak można to zrobić w ten sposób.
źródło
źródło