Daftar efisien dari string unik C #

86

Apa cara paling efisien untuk menyimpan daftar string yang mengabaikan duplikat? Saya berpikir kamus mungkin paling baik memasukkan string dengan menulis dict [str] = false; dan menghitung melalui tombol sebagai daftar. Apakah itu solusi yang bagus?


sumber

Jawaban:

111

Jika Anda menggunakan .NET 3.5, HashSet akan bekerja untuk Anda.

Kelas HashSet <(Of <(T>)>) menyediakan operasi set kinerja tinggi. Himpunan adalah kumpulan yang tidak berisi elemen duplikat, dan yang elemennya tidak berada dalam urutan tertentu.

JP Alioto
sumber
6
Tapi HashSetakan kehilangan urutan item. Sebuah fitur a Listmenyediakan.
aggsol
5
Tambahan: Ada juga SortedSet <T> yang merupakan HashSet terurut yang nyaman.
WhoIsRich
Perhatikan juga bahwa HashSet tidak dapat diakses melalui indeks, hanya melalui enumerator sebagai lawan dari Daftar.
Andrew
23

Anda dapat melakukan sesuatu seperti ini

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);   
Perpetualcoder
sumber
33
Anda tidak perlu cek Berisi dengan HashSet. Anda bisa langsung memanggil metode Add dan itu akan mengembalikan true atau false tergantung pada apakah item tersebut sudah ada atau tidak.
LukeH
1
Jawaban harus diedit untuk menghapus panggilan ke Berisi yang berlebihan. Ini semua yang Anda perlukan agar contoh di atas berfungsi: var collectionWithDup = new [] {"one", "one", "two", "one", "two", "zero"}; var uniqueValues ​​= HashSet baru <string> (collectionWithDup);
pengguna3285954
14

Saya tidak yakin apakah ini dianggap sebagai jawaban yang baik, tetapi ketika dihadapkan dengan kebutuhan akan rangkaian unik yang mempertahankan urutan penyisipan, saya berkompromi dengan HashSet dan Daftar secara berdampingan. Dalam kasus ini, setiap kali Anda menambahkan ke set, lakukan hal berikut:

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

Saat menghapus item, pastikan untuk menghapusnya dari keduanya. Jadi, selama Anda dapat yakin bahwa tidak ada item lain yang ditambahkan ke daftar, Anda akan memiliki set unik berurutan penyisipan!

scone
sumber
10

Anda juga bisa menggunakan Linq seperti pada:

using System.Linq;

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

List<string> distinctItems = items.Distinct().ToList();
Dave Hollingsworth
sumber
8

Gunakan HashSet, tidak perlu memeriksa .Contains (), cukup tambahkan item Anda dalam daftar dan jika duplikatnya tidak akan menambahkannya.

   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
Priyang
sumber
2

Ini bukan bagian dari namespace sistem tetapi telah menggunakan Iesi.Collections dari http://www.codeproject.com/KB/recipes/sets.aspx dengan NHibernate. Ini memiliki dukungan untuk set hash bersama dengan set yang diurutkan, set kamus, dan sebagainya. Karena telah digunakan dengan NHibernate, ini telah digunakan secara ekstensif dan sangat stabil. Ini juga tidak membutuhkan .Net 3.5

AndrewB
sumber
2

Berikut adalah solusi lain tanpa menggunakan HashSet.

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

Itu diadopsi dari utas ini: javascript - Nilai unik dalam larik

Uji:

using FluentAssertions;

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

Uji kinerja untuk List, HashSetdan SortedSet. 1 juta iterasi:

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

Uji kode sumber (intisari)

Alexey Solonets
sumber