Эффективный список уникальных строк C #


86

Каков наиболее эффективный способ сохранить список строк, игнорируя любые дубликаты? Я думал, что словарь может лучше всего вставлять строки, написав dict [str] = false; и перечисление ключей в виде списка. Это хорошее решение?

Ответы:


111

Если вы используете .NET 3.5, HashSet должен работать на вас.

Класс HashSet <(Of <(T>)>) обеспечивает высокопроизводительные операции над наборами. Набор - это коллекция, которая не содержит повторяющихся элементов и элементы которой не расположены в определенном порядке.


5
Но a HashSetпотеряет порядок элементов. Функция Listпредоставляет.
aggsol

4
Дополнительно: есть также SortedSet <T>, который представляет собой удобный отсортированный HashSet.
WhoIsRich

Также обратите внимание, что к HashSet нельзя получить доступ через индекс, только через перечислитель, в отличие от списка.
Эндрю

23

Вы можете сделать что-то вроде этого

var hash = new HashSet<string>();
var collectionWithDup = new []{"one","one","two","one","two","zero"}; 

// No need to check for duplicates as the Add method
// will only add it if it doesn't exist already
foreach (var str in collectionWithDup)
    hash.Add(str);   

33
Вам не нужна проверка Contains с HashSet. Вы можете просто вызвать метод Add напрямую, и он вернет true или false в зависимости от того, существует ли элемент уже.
LukeH

1
Ответ должен быть отредактирован, чтобы убрать обращение к избыточному содержанию. Это все, что вам нужно для работы приведенного выше примера: var collectionWithDup = new [] {"one", "one", "two", "one", "two", "zero"}; var uniqueValues ​​= новый HashSet <строка> (collectionWithDup);
user3285954

14

Я не уверен, что это можно считать хорошим ответом, но, столкнувшись с необходимостью создания уникального набора, поддерживающего порядок вставки, я пошел на компромисс с HashSet и List рядом. В этом случае всякий раз, когда вы добавляете в набор, сделайте следующее:

if(hashSet.Add(item))
    orderList.Add(item);

Удаляя предметы, обязательно снимайте их с обоих. Таким образом, до тех пор, пока вы можете быть уверены, что в список больше ничего не добавлялось, у вас будет уникальный набор, упорядоченный по вставке!


10

Вы также можете использовать Linq, как в:

using System.Linq;

var items = new List<string>() { "one", "one", "two", "one", "two", "zero" };

List<string> distinctItems = items.Distinct().ToList();

8

Используйте HashSet, не нужно проверять .Contains (), просто добавьте свои элементы в список, и если он дублируется, он не будет добавлять его.

   HashSet<int> uniqueList = new HashSet<int>();
   uniqueList.Add(1); // List has values 1
   uniqueList.Add(2);  // List has values 1,2
   uniqueList.Add(1);  // List has values 1,2
   Console.WriteLine(uniqueList.Count); // it will return 2

2

Это не часть системного пространства имен, но использовались Iesi.Collections из http://www.codeproject.com/KB/recipes/sets.aspx с NHibernate. Он поддерживает хешированный набор вместе с отсортированным набором, набором словарей и т. Д. Поскольку он использовался с NHibernate, он использовался широко и очень стабильно. Это также не требует .Net 3.5


2

Вот еще одно решение без использования HashSet.

var items = new List<string>() { "one", "one", "two", "one", "two", "zero" };
var uniqueItems = items.Where((item, index) => items.IndexOf(item) == index);

Он был заимствован из этого потока: javascript - Уникальные значения в массиве

Контрольная работа:

using FluentAssertions;

uniqueItems.Count().Should().Be(3);
uniqueItems.Should().BeEquivalentTo("one", "two", "zero");

Тест производительности для List, HashSetи SortedSet. 1 миллион итераций:

List: 564 ms
HashSet: 487 ms
SortedSet: 1932 ms

Исходный код теста (суть)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.