Jak scalić 2 List <T> i usunąć z niego zduplikowane wartości w C #

159

Mam dwie listy Lista, którą muszę połączyć na trzeciej liście i usunąć zduplikowane wartości z tych list

Trochę trudne do wyjaśnienia, więc pozwól mi pokazać przykład tego, jak wygląda kod i czego chcę w rezultacie, w przykładzie używam typu int, a nie klasy ResultAnalysisFileSql.

first_list = [1, 12, 12, 5]

second_list = [12, 5, 7, 9, 1]

Wynik połączenia dwóch list powinien dać następującą listę: result_list = [1, 12, 5, 7, 9]

Zauważysz, że wynik ma pierwszą listę, zawierającą dwie wartości „12”, a wartość second_list ma dodatkową wartość 12, 1 i 5.

ResultAnalysisFileSql, klasa

[Serializable]
    public partial class ResultAnalysisFileSql
    {
        public string FileSql { get; set; }

        public string PathFileSql { get; set; }

        public List<ErrorAnalysisSql> Errors { get; set; }

        public List<WarningAnalysisSql> Warnings{ get; set; }

        public ResultAnalysisFileSql()
        {

        }

        public ResultAnalysisFileSql(string fileSql)
        {
            if (string.IsNullOrEmpty(fileSql)
                || fileSql.Trim().Length == 0)
            {
                throw new ArgumentNullException("fileSql", "fileSql is null");
            }

            if (!fileSql.EndsWith(Utility.ExtensionFicherosErrorYWarning))
            {
                throw new ArgumentOutOfRangeException("fileSql", "Ruta de fichero Sql no tiene extensión " + Utility.ExtensionFicherosErrorYWarning);
            }

            PathFileSql = fileSql;
            FileSql = ObtenerNombreFicheroSql(fileSql);
            Errors = new List<ErrorAnalysisSql>();
            Warnings= new List<WarningAnalysisSql>();
        }

        private string ObtenerNombreFicheroSql(string fileSql)
        {
            var f = Path.GetFileName(fileSql);
            return f.Substring(0, f.IndexOf(Utility.ExtensionFicherosErrorYWarning));
        }


        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            if (!(obj is ResultAnalysisFileSql))
                return false;

            var t = obj as ResultAnalysisFileSql;
            return t.FileSql== this.FileSql
                && t.PathFileSql == this.PathFileSql
                && t.Errors.Count == this.Errors.Count
                && t.Warnings.Count == this.Warnings.Count;
        }


    }

Jakiś przykładowy kod do łączenia i usuwania duplikatów?

Kiquenet
źródło

Odpowiedzi:

288

Czy spojrzałeś na Enumerable.Union

Ta metoda wyklucza duplikaty ze zwracanego zestawu . Zachowanie to różni się od metody Concat, która zwraca wszystkie elementy w sekwencjach wejściowych, w tym duplikaty.

List<int> list1 = new List<int> { 1, 12, 12, 5};
List<int> list2 = new List<int> { 12, 5, 7, 9, 1 };
List<int> ulist = list1.Union(list2).ToList();

// ulist output : 1, 12, 5, 7, 9
Adriaan Stander
źródło
6
@Dr TJ: Czy Twoja klasa personalna implementuje IEqualityComparer <T>? Jeśli tak, musisz sprawdzić metody GetHashCode i Equals. Zobacz sekcję Uwagi w witrynie msdn.microsoft.com/en-us/library/bb341731.aspx .
Tomas Narros
1
Ważna uwaga, ponieważ napotkałem problemy podczas korzystania z tego w 2 różnych kolekcjach: „Nie możesz łączyć dwóch różnych typów, chyba że jeden dziedziczy po drugim” ze stackoverflow.com/a/6884940/410937, co spowodowało cannot be inferred from the usagebłąd.
atconway
30

dlaczego nie po prostu np

var newList = list1.Union(list2)/*.Distinct()*//*.ToList()*/;

och ... według msdn możesz pominąć plik.Distinct()

Ta metoda wyklucza duplikaty ze zwracanego zestawu

Andreas Niedermair
źródło
25

Unia nie ma dobrych wyników: w tym artykule opisano porównanie ich ze sobą

var dict = list2.ToDictionary(p => p.Number);
foreach (var person in list1)
{
        dict[person.Number] = person;
}
var merged = dict.Values.ToList();

Listy i LINQ seryjnej: 4820ms
słownik seryjnej: 16ms
HashSet i IEqualityComparer: 20ms
LINQ Unię i IEqualityComparer: 24ms

fateme maddahi
źródło
1
Kolejna korzyść z używania scalania słowników -> Mam dwie listy pochodzące z danych DB. Moje dane mają pole sygnatury czasowej, które jest inne na obu listach danych. Dzięki unii otrzymuję duplikaty, ponieważ sygnatura czasowa jest inna. Ale dzięki scaleniu mogę zdecydować, które unikalne pole chcę wziąć pod uwagę w słowniku. +1
JimSan
Może się różnić w zależności od szybkości procesora, w zależności od rodzaju posiadanego procesora.
Asad Ali
7
Na końcu artykułu jest napisane: „Wolę LINQ Union, ponieważ bardzo wyraźnie przekazuje intencje”. ;) (również różnica była tylko 8 ms)
James Wilkins,
1
W przypadku małych list, w których różnica jest nieistotna, Unionkod jest bardziej przejrzysty i czytelny. Poświęcanie czasu na hiperoptymalizację kodu, gdy nie jest wolny, może wiązać się z karą za konserwację w przyszłości.
elolos
14

Użyj Union Linq:

using System.Linq;
var l1 = new List<int>() { 1,2,3,4,5 };
var l2 = new List<int>() { 3,5,6,7,8 };
var l3 = l1.Union(l2).ToList();
Robert Jeppesen
źródło
11
    List<int> first_list = new List<int>() {
        1,
        12,
        12,
        5
    };

    List<int> second_list = new List<int>() {
        12,
        5,
        7,
        9,
        1
    };

    var result = first_list.Union(second_list);
Faizan S.
źródło