Bộ sưu tập chỉ cho phép các mục duy nhất trong .NET?


103

Có bộ sưu tập nào trong C # sẽ không cho phép bạn thêm các mục trùng lặp vào nó không? Ví dụ, với lớp ngớ ngẩn của

public class Customer {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }

    public override int GetHashCode() {
        return (FirstName + LastName + Address).GetHashCode();
    }

    public override bool Equals(object obj) {
        Customer C = obj as Customer;
        return C != null && String.Equals(this.FirstName, C.FirstName) && String.Equals(this.LastName, C.LastName) && String.Equals(this.Address, C.Address);
    }
}

Đoạn mã sau (rõ ràng) sẽ đưa ra một ngoại lệ:

Customer Adam = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Customer AdamDup = new Customer { Address = "A", FirstName = "Adam", LastName = "" };

Dictionary<Customer, bool> CustomerHash = new Dictionary<Customer, bool>();
CustomerHash.Add(Adam, true);
CustomerHash.Add(AdamDup, true);

Nhưng có lớp nào sẽ đảm bảo tính duy nhất tương tự, nhưng không có KeyValuePairs không? Tôi nghĩ HashSet<T>sẽ làm điều đó, nhưng sau khi đọc tài liệu, có vẻ như lớp chỉ là một triển khai thiết lập ( xem hình ).


4
Tôi không hiểu vấn đề của bạn với HashSet<T>. MSDN cho biết "Lớp HashSet <T> cung cấp các hoạt động tập hợp hiệu suất cao. Tập hợp là một tập hợp không chứa các phần tử trùng lặp và các phần tử của chúng không theo thứ tự cụ thể."
Daniel Hilgarth

5
Bạn có thể giải thích thêm tại sao HashSet<T>là không đủ?
JaredPar

@mootinator: Dictionary<K,V>Lớp học không đảm bảo bất kỳ loại thứ tự nào.
LukeH

3
Tôi đoán anh ấy chỉ muốn ném một ngoại lệ khi bạn cố gắng thêm một giá trị hiện có ... Để làm điều này, chỉ cần kiểm tra giá trị bool được trả về từ HashSet<T>.Addphương thức và ném khi false...
digEmAll

2
Nó cũng thực sự khuyên bạn chỉ nên quá tải đối với những loại không thay đổi . Một Khách hàng có thể thay đổi thường sẽ tốt hơn với bình đẳng Tham chiếu mặc định.
Henk Holterman

Câu trả lời:


205

HashSet<T>là những gì bạn đang tìm kiếm. Từ MSDN (nhấn mạnh thêm):

Các HashSet<T>lớp học cung cấp bộ hoạt động hiệu suất cao. Tập hợp là tập hợp không chứa các phần tử trùng lặp và các phần tử của chúng không theo thứ tự cụ thể.

Lưu ý rằng HashSet<T>.Add(T item)phương thức trả về a bool- truenếu mục đã được thêm vào bộ sưu tập; falsenếu mặt hàng đã có mặt.


9
Mục T trong trường hợp này sẽ triển khai giao diện IEquatable. Nếu lớp không kế thừa giao diện này, HashSet <T> sẽ thêm các phần tử trùng lặp.
Rudolf Dvoracek

Hoặc thay vì thực hiện mục IEquatable, bạn có thể chuyển một thể hiện (tùy chỉnh) EqualityComparer<T>cho phương thức HashSet<T>khởi tạo.
Sipke Schoorstra

17

Làm thế nào về chỉ một phương thức mở rộng trên HashSet?

public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
    if (!hash.Add(item))
        throw new ValueExistingException();
}

13

Từ HashSet<T>trang trên MSDN:

Lớp HashSet (Of T) cung cấp các hoạt động tập hợp hiệu suất cao. Tập hợp là tập hợp không chứa các phần tử trùng lặp và các phần tử của chúng không theo thứ tự cụ thể.

(nhấn mạnh của tôi)


4

Nếu tất cả những gì bạn cần là đảm bảo tính duy nhất của các phần tử, thì HashSet chính là thứ bạn cần.

Ý bạn là gì khi bạn nói "chỉ là một cài đặt triển khai"? Tập hợp (theo định nghĩa) là một tập hợp các phần tử duy nhất không lưu thứ tự phần tử.


Bạn hoàn toàn đúng; câu hỏi khá ngu ngốc. Về cơ bản, tôi đang tìm kiếm thứ gì đó sẽ tạo ra một ngoại lệ khi một bản sao được thêm vào (như Dictionary <TKey, TValue>), nhưng như đã đề cập, HashSet <T> trả về false trên một bản sao chép. +1, cảm ơn bạn.
Adam Rackis


3

Chỉ để thêm 2 xu của tôi ...

nếu bạn cần một ValueExistingException, HashSet<T>bạn cũng có thể tạo bộ sưu tập của mình một cách dễ dàng:

public class ThrowingHashSet<T> : ICollection<T>
{
    private HashSet<T> innerHash = new HashSet<T>();

    public void Add(T item)
    {
        if (!innerHash.Add(item))
            throw new ValueExistingException();
    }

    public void Clear()
    {
        innerHash.Clear();
    }

    public bool Contains(T item)
    {
        return innerHash.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        innerHash.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return innerHash.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        return innerHash.Remove(item);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return innerHash.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

điều này có thể hữu ích, chẳng hạn như nếu bạn cần nó ở nhiều nơi ...


Chắc chắn rồi. Tôi đang tự hỏi liệu có gì được tích hợp sẵn hay không, nhưng cảm ơn bạn +1
Adam Rackis

0

Bạn có thể xem xét một số loại Danh sách duy nhất như sau

public class UniqueList<T>
{
    public List<T> List
    {
        get;
        private set;
    }
    List<T> _internalList;

    public static UniqueList<T> NewList
    {
        get
        {
            return new UniqueList<T>();
        }
    }

    private UniqueList()
    {            
        _internalList = new List<T>();
        List = new List<T>();
    }

    public void Add(T value)
    {
        List.Clear();
        _internalList.Add(value);
        List.AddRange(_internalList.Distinct());
        //return List;
    }

    public void Add(params T[] values)
    {
        List.Clear();
        _internalList.AddRange(values);
        List.AddRange(_internalList.Distinct());
       // return List;
    }

    public bool Has(T value)
    {
        return List.Contains(value);
    }
}

và bạn có thể sử dụng nó như sau

var uniquelist = UniqueList<string>.NewList;
uniquelist.Add("abc","def","ghi","jkl","mno");
uniquelist.Add("abc","jkl");
var _myList = uniquelist.List;

sẽ chỉ "abc","def","ghi","jkl","mno"luôn trả về ngay cả khi các bản sao được thêm vào nó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.