2012-02-09 14 views
5

Mam listę. Z ważnych powodów wielokrotnie duplikuję Listę i używam go do różnych celów. W pewnym momencie muszę sprawdzić, czy zawartość wszystkich tych kolekcji jest taka sama.sposób sprawdzania zawartości kolekcji (> 2) są takie same

Cóż, wiem, jak to zrobić. Ale będąc fanem kodowania "short hand" (linq ...) chciałbym wiedzieć, czy mogę to sprawdzić WYDAJNIE z najkrótszą liczbą linii kodu.

List<string> original, duplicate1, duplicate2, duplicate3, duplicate4 
             = new List<string(); 

     //...some code..... 
     bool isequal = duplicate4.sequenceequal(duplicate3) 
     && duplicate3.sequenceequal(duplicate2) 
     && duplicate2.sequenceequal(duplicate1) 
     && duplicate1.sequenceequal(original);//can we do it better than this 

UPDATE

Codeinchaos wskazał pewne senarios I miałaś myśli (duplikatów i kolejność listy) .Though sequenceequal zajmie duplikatów kolejność na liście może być problem. Zmieniam kod w następujący sposób. Muszę skopiować listy dla tego.

List<List<string>> copy = new List<List<int>> { duplicate1, duplicate2, 
               duplicate3, duplicate4 }; 
bool iseqaul = (original.All(x => (copy.All(y => y.Remove(x)))) 
             && copy.All(n => n.Count == 0)); 

Update2

Dzięki Eric-użyciu HashSet może być bardzo skuteczny w następujący sposób. Nie przykryje to jednak duplikatów.

List<HashSet<string>> copy2 =new List<HashSet<string>>{new HashSet<string>(duplicate1), 
                 new HashSet<string>(duplicate2), 
                 new HashSet<string> duplicate3), 
                 new HashSet<string>(duplicate4)}; 
    HashSet<string> origninalhashset = new HashSet<string>(original); 
    bool eq = copy2.All(x => origninalhashset.SetEquals(x)); 

UPDATE3 Dzięki Eric - Oryginalny kod w tym poście z SequenceEqual będzie współpracować z sortowania. Ponieważ Sequenceequal uwzględni kolejność zbiorów, zbiory muszą zostać posortowane przed wywołaniem sequenceequal. Domyślam się, że to nie jest dużo probelmu, ponieważ sortowanie jest dość szybkie (nlogn).

UPDATE4 Zgodnie z sugestią Briana, mogę użyć odnośnika do tego.

var originallkup = original.ToLookup(i => i);  
var lookuplist = new List<ILookup<int, int>> 
            { duplicate4.ToLookup(i=> i), 
             duplicate3.ToLookup(i=> i), 
             duplicate2.ToLookup(i=> i), 
             duplicate1.ToLookup(i=> i) 
            }; 

bool isequal = (lookuplist.Sum(x => x.Count) == (originallkup.Count * 4)) &&  
    (originallkup.All(x => lookuplist.All(i => i[x.Key].Count() == x.Count()))); 

Dziękuję wszystkim za odpowiedzi.

+1

Czy kolejność jest ważna? A może tylko treść? – weston

+0

@ weston-tylko zawartość jest ważna – Jimmy

+3

"Wydajność" lub "najkrótsza liczba linii kodu" Wybierz jedną – weston

Odpowiedz

7

Mam listę. Powielam listę wiele razy i używam jej do różnych celów.W pewnym momencie muszę sprawdzić, czy zawartość wszystkich tych kolekcji jest taka sama.

commenter następnie pyta:

jest kolejność jest ważna? A może tylko treść?

I odpowiedzieć:

tylko treść jest ważna

W takim przypadku używasz złą strukturę danych w pierwszej kolejności. Użyj HashSet<T>, a nie List<T>, do reprezentowania kolekcji nieuporządkowanej, która musi być tanio porównywana z dla zestawu o równości.

Gdy masz już wszystko w hasłach zamiast w listach, możesz po prostu użyć ich metody SetEquals, aby sprawdzić, czy jakakolwiek para zestawów jest nierówna.

Alternatywnie: zachowaj wszystko na listach, aż do momentu, w którym chcesz porównać dla równości. Zainicjuj zestaw skrótu z jednej z list, a następnie użyj SetEquals, aby porównać zestaw mieszający z każdą inną listą.

+0

@ Eric-You masz absolutną rację. Moje obawy dotyczą tylko duplikatów (ponieważ hashset nie będzie duplikować) – Jimmy

+1

@ Jimmy: Użyj klawisza odwzorowania słownika, aby wycenić. Niech klucz będzie elementem, a wartość będzie liczbą. Aby sprawdzić zawartość jest taka sama, po prostu sprawdź, czy słowniki mają pasującą długość (która wskaże liczbę różnych elementów), następnie dla każdego klucza w dyktacie 1 sprawdź, czy 'dict2.TryGetValue (klucz, liczba na wyjściu) && count == dict1 [klawisz] '. – Brian

+0

@ Brian - jeśli to zrobię, muszę napisać opakowanie i obsłużyć duplikaty jako liczbę w słowniku podczas mufiowania przedmiotów. Nie chciałbym tego. – Jimmy

4

Szczerze nie mogę myśleć o bardziej efektywne rozwiązania, ale jeśli chodzi o zmniejszenie liczby linii kodu, dać to bash:

var allLists = new List<List<string>>() { original, duplicate1, duplicate2, duplicate3, duplicate4 }; 

bool allEqual = allLists.All(l => l.SequenceEqual(original)); 

Lub użyć operatora Any - może być lepiej warunki wykonania.

bool allEqual = !allLists.Any(l => !l.SequenceEqual(original)); 

EDIT: potwierdzone, Any zatrzyma wyliczanie źródło raz określa wartość. Dziękuję MSDN.

EDYCJA # 2: Szukałem wydajności SequenceEquals. This guy ma dobry post porównując SequenceEquals z bardziej bezwzględną funkcją. Zmodyfikowałem jego przykład do pracy z List<string>, a moje wyniki pasują do niego. Wydaje się, że jeśli chodzi o wydajność, SequenceEquals nie znajduje się wysoko na liście preferowanych metod.

+0

Nie jestem pewien, czy 'SequenceEquals' ma wcześniejszą wartość odniesienia dla odniesienia, ale jeśli nie, ręczne sprawdzenie sprawi, że kod będzie trochę szybszy. – CodesInChaos

+0

@CodeInChaos: Dzięki, nie myślałem o wcześniejszym wyjściu. Myślę, że "Any" może być lepszym posunięciem w tym przypadku. Zobacz moją zredagowaną odpowiedź. – tobias86

+1

Nie mówiłem o takich wczesnych etapach. Jestem pewien, że "Wszystko" już to robi. Miałem na myśli 'l => (obiekt.ReferenceEquals (l, oryginał) || l.SequenceEqual (oryginalny) '. Ale nie jestem pewien, czy to też konieczne. – CodesInChaos

Powiązane problemy