จะรักษา Unique List ใน Java ได้อย่างไร?


104

จะสร้างรายการของอ็อบเจ็กต์ที่ไม่ซ้ำกัน / ไม่ซ้ำกัน (ไม่ซ้ำกัน) ใน Java ได้อย่างไร?

ตอนนี้ฉันใช้HashMap<String, Integer>เพื่อทำสิ่งนี้เนื่องจากคีย์ถูกเขียนทับและในตอนท้ายเราจะได้รับHashMap.getKeySet()ซึ่งจะไม่ซ้ำกัน แต่ฉันแน่ใจว่าควรจะมีวิธีที่ดีกว่านี้เนื่องจากส่วนของมูลค่านั้นเสียไป

คำตอบ:


165

คุณสามารถใช้การใช้งานชุด :

ข้อมูลบางส่วนจาก JAVADoc:

คอลเลกชันที่มีไม่มีองค์ประกอบที่ซ้ำกัน อย่างเป็นทางการชุดไม่มีคู่ขององค์ประกอบ e1 และ e2 เช่นที่ e1.equals (e2) และองค์ประกอบ null มากที่สุดหนึ่งรายการ โดยนัยของชื่ออินเทอร์เฟซนี้จะจำลองชุดนามธรรมทางคณิตศาสตร์

หมายเหตุ:ต้องใช้ความระมัดระวังอย่างยิ่งหากใช้วัตถุที่เปลี่ยนแปลงได้เป็นองค์ประกอบชุด ไม่ได้ระบุลักษณะการทำงานของชุดหากค่าของวัตถุมีการเปลี่ยนแปลงในลักษณะที่มีผลต่อการเปรียบเทียบที่เท่าเทียมกันในขณะที่วัตถุเป็นองค์ประกอบในชุด กรณีพิเศษของข้อห้ามนี้คือไม่อนุญาตให้ชุดมีตัวเองเป็นองค์ประกอบ `

นี่คือการใช้งาน:

  • แฮชเซ็ต

    คลาสนี้นำเสนอประสิทธิภาพของเวลาคงที่สำหรับการดำเนินการพื้นฐาน (เพิ่มลบมีและขนาด) โดยสมมติว่าฟังก์ชันแฮชจะกระจายองค์ประกอบอย่างเหมาะสมระหว่างที่เก็บข้อมูล การวนซ้ำชุดนี้ต้องใช้เวลาตามสัดส่วนกับผลรวมของขนาดอินสแตนซ์ HashSet (จำนวนองค์ประกอบ) บวกกับ "ความจุ" ของอินสแตนซ์ HashMap สำรอง (จำนวนที่เก็บข้อมูล) ดังนั้นจึงเป็นเรื่องสำคัญมากที่จะต้องไม่ตั้งค่าความจุเริ่มต้นสูงเกินไป (หรือโหลดแฟกเตอร์ต่ำเกินไป) หากประสิทธิภาพการทำซ้ำมีความสำคัญ

    เมื่อการวนซ้ำHashSetลำดับขององค์ประกอบที่ให้ผลจะไม่ได้กำหนดไว้

  • LinkedHashSet

    ตารางแฮชและการใช้งานรายการที่เชื่อมโยงของอินเทอร์เฟซ Set พร้อมลำดับการทำซ้ำที่คาดเดาได้ การใช้งานนี้แตกต่างจาก HashSet ตรงที่มีการเก็บรักษารายการที่เชื่อมโยงแบบทวีคูณซึ่งรันผ่านรายการทั้งหมด รายการที่เชื่อมโยงนี้กำหนดลำดับการวนซ้ำซึ่งเป็นลำดับที่องค์ประกอบถูกแทรกลงในชุด (ลำดับการแทรก) โปรดทราบว่าลำดับการแทรกจะไม่ได้รับผลกระทบหากมีการใส่องค์ประกอบเข้าไปในชุดอีกครั้ง (อิลิเมนต์ e ถูกใส่เข้าไปในเซต s อีกครั้งถ้า s.add (e) ถูกเรียกใช้เมื่อ s.contains (e) จะคืนค่าจริงทันทีก่อนที่จะเรียกใช้)

    ดังนั้นผลลัพธ์ของโค้ดด้านบน ...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }

    ... จะต้องเป็น

    3
    1
    2
  • ทรีเซ็ต

    การใช้งานนี้ให้การรับประกันต้นทุนเวลา log (n) สำหรับการดำเนินการพื้นฐาน (เพิ่มลบและมี) โดยค่าเริ่มต้นองค์ประกอบที่ส่งคืนเมื่อทำซ้ำจะเรียงลำดับตาม "การเรียงลำดับตามธรรมชาติ " ดังนั้นโค้ดด้านบน ...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }

    ... จะแสดงผลลัพธ์นี้:

    1
    2
    3

    (คุณยังสามารถส่งผ่านComparatorอินสแตนซ์ไปยังตัวTreeSetสร้างได้โดยจัดเรียงองค์ประกอบตามลำดับที่แตกต่างกัน)

    โปรดทราบว่าลำดับที่ดูแลโดยชุด (ไม่ว่าจะมีการจัดเตรียมตัวเปรียบเทียบที่ชัดเจนหรือไม่ก็ตาม) จะต้องสอดคล้องกับค่าเท่ากับถ้าจะใช้อินเทอร์เฟซ Set อย่างถูกต้อง (ดูการเปรียบเทียบหรือตัวเปรียบเทียบสำหรับคำจำกัดความที่แม่นยำของความสอดคล้องกับเท่ากับ) เนื่องจากอินเทอร์เฟซ Set ถูกกำหนดในแง่ของการดำเนินการที่เท่าเทียมกัน แต่อินสแตนซ์ TreeSet ทำการเปรียบเทียบองค์ประกอบทั้งหมดโดยใช้วิธีการ CompareTo (หรือเปรียบเทียบ) ดังนั้นสอง องค์ประกอบที่ถือว่าเท่ากันโดยวิธีนี้คือจากมุมมองของเซตเท่ากับ พฤติกรรมของเซตมีการกำหนดไว้อย่างชัดเจนแม้ว่าลำดับของเซตจะไม่สอดคล้องกับค่าเท่ากับ เพียงแค่ไม่ปฏิบัติตามสัญญาทั่วไปของอินเทอร์เฟซ Set


ตอนนี้กำลังสับสนจะใช้อันไหนดี ฉันแค่ต้องรักษารายการสตริงที่ไม่ซ้ำกัน ดังนั้นโดยพื้นฐานแล้วแม้ว่าจะมีการเพิ่มสตริงที่มีอยู่แล้วก็ควรเพิ่มเข้าไป

1
ทางเลือกเป็นของคุณ ... HashSet เป็นสากลและรวดเร็วสั่งซื้อชุดต้นไม้ LinkedHashset เก็บคำสั่งแทรก ...
แฟรงค์

6
นี่ไม่ใช่ LIST ... ดังนั้นจึงไม่มีวิธีการเชื่อมต่อ LIST ทั้งหมด
marcolopes

2
ชุดไม่ใช่รายการฉันไม่สามารถค้นหาองค์ประกอบด้วยดัชนีในชุดใน O (1) เวลา (การเข้าถึงโดยสุ่ม)
wilmol

13

ฉันต้องการชี้แจงบางสิ่งที่นี่สำหรับผู้โพสต์ต้นฉบับที่คนอื่นพูดถึง แต่ยังไม่ได้ระบุไว้อย่างชัดเจน เมื่อคุณบอกว่าคุณต้องการ Unique List นั่นคือคำจำกัดความของชุดคำสั่งซื้อ ความแตกต่างที่สำคัญอื่น ๆ ระหว่าง Set Interface และอินเทอร์เฟซ List คือ List อนุญาตให้คุณระบุดัชนีแทรก คำถามคือคุณต้องการอินเทอร์เฟซรายการ (เช่นสำหรับความเข้ากันได้กับไลบรารีของบุคคลที่สามเป็นต้น) หรือคุณสามารถออกแบบซอฟต์แวร์ของคุณใหม่เพื่อใช้อินเทอร์เฟซ Set ได้หรือไม่? คุณต้องพิจารณาด้วยว่าคุณกำลังทำอะไรกับอินเทอร์เฟซ การค้นหาองค์ประกอบตามดัชนีมีความสำคัญหรือไม่? คุณคาดหวังกี่องค์ประกอบในชุดของคุณ? หากคุณกำลังจะมีองค์ประกอบหลายอย่างการสั่งซื้อสำคัญหรือไม่?

หากคุณต้องการ List ที่มีข้อ จำกัด ที่ไม่เหมือนใครมีคลาส Apache Common Utils org.apache.commons.collections.list.SetUniqueList ซึ่งจะให้อินเทอร์เฟซรายการและข้อ จำกัด เฉพาะ โปรดทราบว่านี่เป็นการทำลายอินเทอร์เฟซรายการ อย่างไรก็ตามคุณจะได้รับประสิทธิภาพที่ดีขึ้นจากสิ่งนี้หากคุณต้องการค้นหารายการตามดัชนี หากคุณสามารถจัดการกับอินเทอร์เฟซ Set ได้และคุณมีชุดข้อมูลที่เล็กลง LinkedHashSet อาจเป็นวิธีที่ดี ขึ้นอยู่กับการออกแบบและเจตนาของซอฟต์แวร์ของคุณ

อีกครั้งมีข้อดีและข้อเสียบางประการสำหรับแต่ละคอลเลกชัน แทรกเร็ว แต่อ่านช้าบางส่วนอ่านเร็ว แต่แทรกช้าเป็นต้นควรใช้เวลาพอสมควรกับเอกสารประกอบคอลเลคชันเพื่อเรียนรู้รายละเอียดปลีกย่อยของแต่ละคลาสและอินเทอร์เฟซอย่างเต็มที่


3
สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม จะวิจารณ์หรือการร้องขอคำชี้แจงจากผู้เขียนแสดงความคิดเห็นด้านล่างโพสต์ของพวกเขา - คุณสามารถแสดงความคิดเห็นในโพสต์ของคุณเองและเมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด
Zach Saucier

1
มันให้คำตอบจริง หากเขาต้องการเพียงแค่รายการที่ทำหน้าที่เหมือน Set ให้ใช้ org.apache.commons.collections.list.SetUniqueList แต่ในฐานะโปรแกรมเมอร์เขา / เราควรระมัดระวังมากกว่านั้นและควรคิดถึงปัญหาให้มากขึ้น หากสิ่งนี้ทำให้คำตอบของฉันดีขึ้น "จะสร้างรายการเฉพาะใน Java ได้อย่างไร" List uniqueList = setUniqueList ใหม่ (); นั่นคือวิธีการ ....
Paul Connolly

3
และซัคฉันไม่ได้พยายามที่จะเป็นคนขี้เหวี่ยง แต่คุณได้อ่านคำตอบของฉันก่อนความคิดเห็นของคุณหรือไม่? หรือคุณไม่เข้าใจ? หากคุณไม่เข้าใจก็ไม่เป็นไร - แจ้งให้เราทราบแล้วฉันจะขยายความในหัวข้อนี้ ฉันไม่คิดว่าฉันควรต้องเขียนบทความเกี่ยวกับโครงสร้างข้อมูลเพื่อให้คำตอบที่เป็นมิตรกับคำถามของใครบางคน ฉันไม่สนใจที่จะใช้วิธีที่อ่อนโยนในการสร้างชื่อเสียงความคิดเห็นของฉันเมื่อฉันรู้คำตอบและไม่มีใครให้คำตอบจริงๆ
Paul Connolly

1
และอย่างไรก็ตามฉันไม่ได้วิจารณ์หรือขอคำชี้แจงจากผู้เขียนฉันแค่บอกว่าเขาสามารถ A) ใช้ชั้นเรียนที่ฉันให้เขาได้อย่างรวดเร็วหรือ B) ใช้เวลาทำความเข้าใจกับความแตกต่างระหว่างชั้นเรียนเหล่านี้และเกี่ยวข้อง ตามความต้องการของเขา เห็นได้ชัดว่า B ใช้เวลานานกว่า แต่จะส่งผลให้โค้ดดีขึ้นในระยะยาว
Paul Connolly

9

ใช้new HashSet<String> ตัวอย่าง:

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}

2
เพียงแค่เพิ่มโปรแกรมข้างต้น -> ต้องส่งจดหมาย 11 ฉบับไปที่: [Aaron, Alice, James, Adel, Jose, Jeremy, Amy, Alan, Patrick, Helen, Alexi]
Ammad

4

คุณสามารถใช้HashSet<String>เพื่อรักษาคอลเล็กชันของวัตถุที่ไม่ซ้ำใคร หากIntegerค่าในแผนที่ของคุณมีความสำคัญคุณสามารถใช้containsKeyวิธีการแผนที่เพื่อทดสอบว่าคีย์ของคุณอยู่ในแผนที่แล้วหรือไม่


3

HashSet<String>(หรือ) Setการนำไปใช้งานใด ๆอาจได้ผลสำหรับคุณ Setไม่อนุญาตให้มีการทำซ้ำ

นี่คือjavadocสำหรับ HashSet


2

ฉันไม่รู้ว่าสิ่งนี้มีประสิทธิภาพเพียงใดอย่างไรก็ตามใช้ได้กับฉันในบริบทง่ายๆ

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }

1

คุณอาจต้องการใช้หนึ่งในคลาสการใช้งานของjava.util.Set<E>อินเตอร์เฟสเช่นjava.util.HashSet<String> คลาสคอลเลกชัน

คอลเล็กชันที่ไม่มีองค์ประกอบซ้ำกัน อย่างเป็นทางการชุดไม่มีคู่ขององค์ประกอบ e1 และ e2 เช่นที่ e1.equals (e2) และองค์ประกอบ null มากที่สุดหนึ่งรายการ โดยนัยของชื่ออินเทอร์เฟซนี้จะจำลองชุดนามธรรมทางคณิตศาสตร์

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