มีลำดับการเก็บรักษา Set ที่ใช้รายการด้วยหรือไม่


85

ฉันกำลังพยายามค้นหาการนำไปใช้java.util.Listและjava.util.Setในเวลาเดียวกันใน Java ฉันต้องการให้คลาสนี้อนุญาตเฉพาะองค์ประกอบที่ไม่ซ้ำกัน (เป็นSet) และรักษาลำดับของพวกเขา (เช่นList) มีอยู่ใน JDK 6 หรือไม่?

สิ่งสำคัญคือต้องมีList<T>#add(int, T)เพื่อให้ฉันสามารถแทรกลงในตำแหน่งเฉพาะได้


คุณหมายถึงรักษาลำดับการแทรกหรือบางคำสั่งที่กำหนดโดย a Comparator? คุณต้องการความหมายของListอินเทอร์เฟซด้วยหรือไม่?

คำตอบ:


208

TreeSetเรียงตามลำดับองค์ประกอบ LinkedHashSetยังคงรักษาลำดับการแทรก หวังว่าหนึ่งในนั้นคือสิ่งที่คุณเป็น

คุณได้ระบุว่าคุณต้องการแทรกในสถานที่ที่กำหนดเองฉันสงสัยว่าคุณจะต้องเขียนของคุณเอง - เพียงแค่สร้างคลาสที่มี a HashSet<T>และArrayList<T>; เมื่อเพิ่มรายการให้ตรวจสอบว่าอยู่ในชุดหรือไม่ก่อนที่จะเพิ่มลงในรายการ

อีกทางเลือกหนึ่งของข้อเสนอคอมมอนส์คอลเลกชัน 4 ของ Apache ListOrderedSetและSetUniqueListซึ่งทำงานในลักษณะเดียวกันและควรเป็นไปตามข้อกำหนดที่กำหนด



12

คุณหมายถึงชอบLinkedHashSet? สิ่งนี้จะรักษาลำดับการเข้า แต่ไม่อนุญาตให้มีการทำซ้ำ

IMHO เป็นข้อกำหนดที่ผิดปกติ แต่คุณสามารถเขียนรายการโดยไม่ซ้ำกัน

class SetList<T> extends ArrayList<T> {
    @Override
    public boolean add(T t) {
        return !super.contains(t) && super.add(t);
    }

    @Override
    public void add(int index, T element) {
        if (!super.contains(element)) super.add(index, element);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            added |= add(t);
        return added;
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            if (!super.contains(t)) {
                super.add(index++, t);
                added = true;
            }
        return added;
    }
}

มันไม่ได้ใช้Listอินเทอร์เฟซดูการเปลี่ยนแปลงของฉันกับคำถาม
yegor256

2
stackoverflow.com/a/8185105/253468ดูดีกว่าเพราะไม่มีO(n)ความซับซ้อนในการแทรกมีข้อเสียที่ต้องพิจารณาระหว่างการจัดเก็บข้อมูลคู่และการO(log(n))แทรก
TWiStErRob

8

คุณไม่สามารถดำเนินการได้ListและSetในครั้งเดียวโดยไม่มีการละเมิดสัญญา ดูตัวอย่างเช่นSet.hashCodeสัญญา:

รหัสแฮชของชุดถูกกำหนดให้เป็นผลรวมของรหัสแฮชขององค์ประกอบในชุดโดยที่รหัสแฮชขององค์ประกอบ null ถูกกำหนดให้เป็นศูนย์

ในทางกลับกันนี่คือสัญญาของList.hashCode:

รหัสแฮชของรายการถูกกำหนดให้เป็นผลลัพธ์ของการคำนวณต่อไปนี้:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

ดังนั้นจึงเป็นไปไม่ได้ที่จะใช้คลาสเดียวซึ่งรับประกันว่าสัญญาทั้งสองจะสำเร็จ ปัญหาเดียวกันสำหรับequalsการนำไปใช้งาน


4

ถ้าคุณจะไม่ จำกัด ตัวเองให้ JDK 6 คุณสามารถใช้อาปาเช่คอลเลกชันที่พบบ่อยห้องสมุดซึ่งข้อเสนอที่แน่นอนตรงกับความต้องการของคุณ - ListOrderedSet มันเหมือนListและSetรวมกัน :)


ลบListอินเทอร์เฟซ
LateralFractal

0

ฉันมีปัญหาที่คล้ายกันดังนั้นฉันจึงเขียนของตัวเอง ดูที่นี่ . การIndexedArraySetขยายArrayListและการดำเนินการSetดังนั้นจึงควรรองรับการดำเนินการทั้งหมดที่คุณต้องการ โปรดทราบว่าการแทรกองค์ประกอบลงในตำแหน่งที่อยู่ตรงกลางArrayListอาจเป็นเรื่องช้าสำหรับรายการใหญ่เนื่องจากจำเป็นต้องย้ายองค์ประกอบต่อไปนี้ทั้งหมด ของฉันIndexedArraySetไม่เปลี่ยนที่


0

อีกทางเลือกหนึ่ง (ลบListข้อกำหนดอินเทอร์เฟซ) คือ Guava ImmutableSetซึ่งรักษาลำดับการแทรก จากหน้าวิกิของพวกเขา :

ยกเว้นคอลเลกชันที่เรียงลำดับคำสั่งซื้อจะถูกเก็บรักษาไว้ตั้งแต่เวลาก่อสร้าง ตัวอย่างเช่น,

ImmutableSet.of("a", "b", "c", "a", "d", "b")

จะวนซ้ำองค์ประกอบของมันตามลำดับ "a", "b", "c", "d"

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