2012-03-08 11 views
9

Nadal jestem całkiem nowy dla C#, ale zauważyłem zalety poprzez posty na forum stosowania HashSet zamiast List w szczególnych przypadkach.Jaka jest najszybsza/najbezpieczniejsza metoda do iteracji w HashSet?

Moja obecna sprawa nie polega na tym, że przechowuję olbrzymią ilość danych w pojedynczym List, ale raczej niż często muszę sprawdzać, czy są to członkowie.

Połów jest taki, że muszę go również powtórzyć, ale kolejność, w jakiej są przechowywane lub pobierane, nie ma znaczenia.

Czytałem, że każda pętla jest wolniejsza niż w następnej, więc jak inaczej mogę to zrobić w najszybszym możliwym sposobie?

Liczba sprawdzeń, które robię, zdecydowanie szkodzi mojej skuteczności z listami, więc przynajmniej w porównaniu z wydajnością HashSet byłaby przydatna.

Edycja: aktualnie używam list, iteruję przez nie w wielu lokalizacjach, a inny kod jest wykonywany w każdej lokalizacji. Najczęściej aktualne listy zawierają współrzędne punktowe, które następnie wykorzystuję w odniesieniu do dwuwymiarowej tablicy, a następnie wykonuję operację lub inną na podstawie kryteriów listy.

Jeśli nie ma bezpośredniej odpowiedzi na moje pytanie, jest to w porządku, ale założyłem, że mogą istnieć inne metody iterowania w cyklu HashSet niż po prostu foreach. W tej chwili nie rozumiem, jakie mogą być inne metody, jakie są ich zalety, itd. Zakładając istnienie innych metod, założyłem również, że istnieje typowa preferowana metoda wyboru, która jest ignorowana tylko wtedy, gdy nie zaspokaja potrzeb (moje potrzeby są dość proste).

Jeśli chodzi o przedwczesną optymalizację, wiem już, że używanie list jest wąskim gardłem. Jak pomóc w rozwiązaniu tego problemu, to gdzie utknąłem. Nawet nie utknąłem dokładnie, ale nie chciałem ponownie wymyślać koła, testując wielokrotnie tylko po to, aby przekonać się, że robię to w najlepszy możliwy sposób (jest to duży projekt z ponad 3-miesięczną inwestycją, listy są wszędzie , ale są zdecydowanie takie, że nie chcę duplikatów, mam dużo danych, nie trzeba ich przechowywać w określonej kolejności itp.).

+1

Co zamierzasz zrobić w iteracji? Wykonywać kod? Policz coś? –

+3

Przedwcześnie optymalizujesz. Nie oznacza to, że powinieneś całkowicie zignorować implikacje wydajności struktur danych i kodu, ale jeśli potrzebujesz semantyki HashSet, następnym krokiem jest profilowanie iteracji w kontekście twojego programu i sposobu, w jaki zwykle będzie to możliwe. biegać. Jeśli iteracja nie jest wąskim gardłem wydajności, a następnie przejść dalej, nie jest warta twojego czasu. Nie zakładajcie, że tak będzie, przetestujcie. –

+1

Nie wiem nic na temat odpowiedzi, ale moja konwencja mówi, że najszybsza metoda nie będzie najbezpieczniejsza, a najbezpieczniejsza nie będzie najszybsza. Sądzę, że jeśli jedna metoda jest najszybsza i najbezpieczniejsza, to nie ma potrzeby stosowania innych metod. Mogę się mylić. – nawfal

Odpowiedz

8

Pętla foreach ma niewielką wartość dodatkowego obciążenia w kolekcjach indeksowanych (takich jak tablica). Dzieje się tak głównie dlatego, że foreach wykonuje trochę więcej sprawdzania niż pętlę for.

HashSet nie ma indeksatora, więc musisz użyć modułu wyliczającego.

W tym przypadku foreach jest skuteczny, ponieważ wywołuje tylko MoveNext(), gdy przechodzi przez kolekcję.

Również Parallel.ForEach może znacznie poprawić wydajność, w zależności od pracy wykonywanej w pętli i rozmiaru HashSet.

Jak wspomniano wcześniej, profilowanie jest najlepszym rozwiązaniem.

4

Nie powinieneś w pierwszej kolejności wykonywać iteracji hashset, aby określić, czy dany element jest w nim. Powinieneś użyć metody HashSet (nie LINQ) zawierającej. HashSet jest zaprojektowany w taki sposób, że nie będzie musiał przeglądać każdego elementu, aby zobaczyć, czy dana wartość znajduje się wewnątrz zestawu. To właśnie czyni go tak potężnym do przeszukiwania Listy.

+6

Mówi w swoim pytaniu, że musi być w stanie zarówno wyszukiwać, jak i iterować, a nie iterować do wyszukiwania. – JamieSee

2

niezupełnie odpowiadając na pytanie w nagłówku, ale bardziej dotycząca konkretnego problemu:

chciałbym zrobić własny Collection obiekt, który wykorzystuje zarówno HashSet i List wewnętrznie. Iterowanie jest szybkie, ponieważ możesz korzystać z Listy, sprawdzanie dla Contains jest szybkie, ponieważ możesz używać HashSet. Po prostu zrób to jako IEnumerable i możesz również użyć tej Kolekcji w foreach.

Wadą jest więcej pamięci, ale są tylko dwa razy więcej odniesień do obiektu, a nie dwa razy więcej obiektów. Najgorszy scenariusz to tylko dwa razy więcej pamięci, ale wydajesz się być bardziej zainteresowany wydajnością.

Dodawanie, sprawdzanie i iteracja są szybkie w ten sposób, tylko usunięcie jest nadal O (N) ze względu na List.

EDYCJA: Jeśli usunięcie musi być również O (1), utwórz listę podwójnych wskaźników i ustaw HashSet jako słownik, aby szybko znaleźć lokalizację obiektu na liście.

0

Miałem ten sam problem, w którym HashSet bardzo dobrze pasuje do dodawania unikalnych elementów, ale jest bardzo powolne, gdy pobiera elementy w pętli for. Rozwiązałem go, przekształcając HashSet w tablicę, a następnie uruchamiając for.

Powiązane problemy