Ефективний перелік унікальних рядків C #


86

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

Відповіді:


111

Якщо ви використовуєте .NET 3.5, HashSet повинен працювати для вас.

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


5
Але а HashSetвтратить порядок предметів. Функція a 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
Відповідь слід відредагувати, щоб видалити дзвінок надлишковим Contains. Це все, що потрібно для роботи наведеного вище прикладу: var collectionWithDup = new [] {"one", "one", "two", "one", "two", "zero"}; var uniqueValues ​​= новий HashSet <string> (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.