คอลเลกชันที่อนุญาตเฉพาะรายการที่ไม่ซ้ำกันใน. NET?


106

มีคอลเล็กชันใน C # ที่จะไม่ให้คุณเพิ่มรายการที่ซ้ำกันหรือไม่? ตัวอย่างเช่นกับชั้นโง่ของ

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);
    }
}

รหัสต่อไปนี้ (ชัดเจน) จะทำให้เกิดข้อยกเว้น:

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);

แต่มีคลาสที่จะรับประกันความเป็นเอกลักษณ์ในทำนองเดียวกัน แต่ไม่มี KeyValuePairs หรือไม่? ฉันคิดว่าHashSet<T>จะทำอย่างนั้น แต่เมื่ออ่านเอกสารแล้วดูเหมือนว่าคลาสจะเป็นเพียงการใช้งานชุดเท่านั้น ( ไปรูป )


4
HashSet<T>ฉันไม่เข้าใจปัญหาของคุณกับ MSDN กล่าวว่า "คลาส HashSet <T> ให้การดำเนินการเซ็ตประสิทธิภาพสูงชุดคือคอลเล็กชันที่ไม่มีองค์ประกอบที่ซ้ำกันและองค์ประกอบที่ไม่มีลำดับใด ๆ "
Daniel Hilgarth

5
คุณช่วยอธิบายเพิ่มเติมHashSet<T>ได้ไหมว่าเหตุใดจึงไม่เพียงพอ
JaredPar

@mootinator: Dictionary<K,V>ชั้นเรียนไม่รับประกันการสั่งซื้อใด ๆ
LukeH

3
ฉันเดาว่าเขาแค่ต้องการยกเว้นเมื่อคุณพยายามเพิ่มค่าที่มีอยู่ ... ในการทำเช่นนี้ให้ตรวจสอบค่าบูลที่ส่งคืนจากHashSet<T>.Addวิธีการและโยนเมื่อfalse...
digEmAll

2
ขอแนะนำอย่างยิ่งให้โอเวอร์โหลดเฉพาะสำหรับประเภทที่ไม่เปลี่ยนรูปเท่านั้น ลูกค้าที่เปลี่ยนแปลงไม่ได้มักจะยุติธรรมดีกว่าด้วยค่าเริ่มต้นของการอ้างอิง - ความเท่าเทียมกัน
Henk Holterman

คำตอบ:


208

HashSet<T>คือสิ่งที่คุณกำลังมองหา จากMSDN (เน้นเพิ่ม):

HashSet<T>ระดับให้การดำเนินงานของชุดที่มีประสิทธิภาพสูง ชุดคือคอลเล็กชันที่ไม่มีองค์ประกอบที่ซ้ำกันและองค์ประกอบที่ไม่เรียงตามลำดับที่เฉพาะเจาะจง

โปรดสังเกตว่าHashSet<T>.Add(T item)เมธอดจะส่งคืน a bool- trueหากเพิ่มไอเท็มลงในคอลเลกชัน falseหากมีรายการอยู่แล้ว


10
T รายการในกรณีนี้ควรใช้อินเทอร์เฟซ IEquatable ถ้าคลาสไม่สืบทอดอินเทอร์เฟซนี้ HashSet <T> จะเพิ่มองค์ประกอบที่ซ้ำกัน
Rudolf Dvoracek

หรือแทนที่จะใช้ไอเท็IEquatableมคุณสามารถส่งผ่านEqualityComparer<T>อินสแตนซ์(กำหนดเอง) ไปยังตัวHashSet<T>สร้าง
Sipke Schoorstra

17

วิธีการขยาย HashSet เป็นอย่างไร

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

13

จากHashSet<T>หน้าบน MSDN:

คลาส HashSet (Of T) ให้การดำเนินการเซ็ตประสิทธิภาพสูง ชุดคือคอลเล็กชันที่ไม่มีองค์ประกอบที่ซ้ำกันและองค์ประกอบที่ไม่เรียงตามลำดับที่เฉพาะเจาะจง

(เน้นเหมือง)


4

หากสิ่งที่คุณต้องการคือเพื่อให้แน่ใจว่าองค์ประกอบที่เป็นเอกลักษณ์ HashSet คือสิ่งที่คุณต้องการ

คุณหมายความว่าอย่างไรเมื่อคุณพูดว่า "ใช้งานเพียงชุดเดียว" ชุดคือ (ตามคำจำกัดความ) ชุดขององค์ประกอบเฉพาะที่ไม่บันทึกลำดับองค์ประกอบ


คุณพูดถูก คำถามนั้นโง่มาก โดยพื้นฐานแล้วฉันกำลังมองหาสิ่งที่จะทำให้เกิดข้อยกเว้นเมื่อมีการเพิ่มรายการที่ซ้ำกัน (เช่น Dictionary <TKey, TValue>) แต่ตามที่กล่าวไปแล้ว HashSet <T> จะส่งคืนเท็จในการเพิ่มที่ซ้ำกัน +1 ขอบคุณครับ
Adam Rackis


3

แค่เพิ่ม 2 เซ็นต์ของฉัน ...

หากคุณต้องการการขว้างแบบ ValueExistingException HashSet<T>คุณสามารถสร้างคอลเลกชันของคุณได้อย่างง่ายดาย:

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();
    }
}

สิ่งนี้มีประโยชน์เช่นหากคุณต้องการใช้งานในหลาย ๆ ที่ ...


แน่นอน ฉันสงสัยว่ามีอะไรอยู่ในตัว แต่ขอขอบคุณ +1
Adam Rackis

0

คุณอาจมองเข้าไปใน Unique List บางประเภทดังต่อไปนี้

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);
    }
}

และคุณสามารถใช้งานได้ดังนี้

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

จะกลับมา"abc","def","ghi","jkl","mno"เสมอแม้ว่าจะมีการเพิ่มรายการที่ซ้ำกันเข้าไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.