โค้ดยิม/จาวาบล็อก/สุ่ม/การลบองค์ประกอบออกจาก ArrayList
John Squirrels
ระดับ
San Francisco

การลบองค์ประกอบออกจาก ArrayList

เผยแพร่ในกลุ่ม
สวัสดี! ในบทเรียนที่แล้ว เราได้ทำความคุ้นเคยกับArrayListชั้นเรียนและเรียนรู้วิธีดำเนินการทั่วไปกับชั้นเรียนนี้ นอกจากนี้ เรายังชี้ให้เห็นความแตกต่างหลายประการระหว่างArrayListอาร์เรย์ธรรมดาและอาร์เรย์ แต่เรามองข้ามหัวข้อหนึ่งไป นั่นคือ วิธีลบองค์ประกอบออกจากไฟล์ArrayList. เราจะหารือกันตอนนี้ การลบองค์ประกอบออกจาก ArrayList - 1เราได้กล่าวไปแล้วว่าการลบองค์ประกอบออกจากอาร์เรย์ธรรมดานั้นไม่สะดวกนัก เนื่องจากเราไม่สามารถลบองค์ประกอบได้ เราจึงทำได้เพียง "ศูนย์ออก" (ตั้งค่าเป็น null) ค่าของมัน:
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Behemoth");
       cats[2] = new Cat("Lionel Messi");

       cats[1] = null;

       System.out.println(Arrays.toString(cats));
   }


@Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
ผลลัพธ์: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] แต่การตั้งค่าองค์ประกอบอาร์เรย์เป็น null ทำให้ "รู" เรายังไม่ได้ลบตำแหน่งในอาร์เรย์ เฉพาะเนื้อหาเท่านั้น ลองนึกภาพว่าจะเกิดอะไรขึ้นถ้าเรามีแมว 50 ตัวและกำจัดพวกมัน 17 ตัวด้วยวิธีนี้ เราจะมีอาร์เรย์ที่มี 17 รู เพียงแค่พยายามติดตามพวกเขา! มันไม่สมจริงที่จะคาดหวังให้จำจำนวนเซลล์ว่างที่คุณสามารถเขียนค่าใหม่ได้ หากคุณทำผิดพลาด คุณจะเขียนทับการอ้างอิงวัตถุที่คุณต้องการ แน่นอนว่ามีวิธีทำอย่างระมัดระวังกว่านี้เล็กน้อย: หลังจากลบองค์ประกอบแล้วให้ย้ายองค์ประกอบไปที่ด้านหน้าของอาร์เรย์เพื่อใส่ "รู" ที่ส่วนท้าย:
public static void main(String[] args) {

   Cat[] cats = new Cat[4];
   cats[0] = new Cat("Thomas");
   cats[1] = new Cat("Behemoth");
   cats[2] = new Cat("Lionel Messi");
   cats[2] = new Cat("Fluffy");

   cats[1] = null;

   for (int i = 2; i < cats.length-1; i++) {
       cats [i-1] = cats [i];// Move the elements to the front of the array, so the empty position is at the end
   }

   System.out.println(Arrays.toString(cats));
}
เอาต์พุต: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] ดูเหมือนจะดีกว่า แต่แทบจะเรียกได้ว่าเป็นโซลูชันที่มีประสิทธิภาพ หากไม่มีเหตุผลอื่นนอกจากความจริงที่ว่าเราต้องเขียนโค้ดนี้ทุกครั้งที่เราลบองค์ประกอบออกจากอาร์เรย์! นี่เป็นตัวเลือกที่ไม่ดี เราสามารถไปอีกทางหนึ่งและสร้างวิธีการแยกต่างหากได้:
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
แต่ก็มีประโยชน์เพียงเล็กน้อย: วิธีนี้ใช้ได้กับ วัตถุ เท่านั้นCatแต่ไม่ใช่ประเภทอื่น กล่าวอีกนัยหนึ่ง ถ้าโปรแกรมมีคลาสอีก 100 คลาสที่เราต้องการใช้กับอาร์เรย์ เราจะต้องเขียนเมธอดเดียวกันโดยใช้ตรรกะเดียวกันทุกประการในแต่ละคลาส นี่มันหายนะชัดๆ -_- แต่ArrayListชั้นแก้ปัญหานี้ได้! มันใช้วิธีการพิเศษในการลบองค์ประกอบ:remove()
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(1);

   System.out.println(cats.toString());
}
เราส่งดัชนีวัตถุของเราไปยังเมธอด ซึ่งจะลบออก (เหมือนกับในอาร์เรย์) วิธีการ นี้remove()มีคุณสมบัติพิเศษสองประการ ประการแรกมันไม่ทิ้ง "รู" มันใช้ตรรกะที่จำเป็นในการเปลี่ยนองค์ประกอบอยู่แล้วเมื่อองค์ประกอบถูกลบออกจากตรงกลาง ซึ่งก่อนหน้านี้เราเขียนเอง ดูผลลัพธ์จากรหัสก่อนหน้า:
[Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
เราย้ายแมวหนึ่งตัวออกจากตรงกลาง และย้ายที่เหลือเพื่อไม่ให้มีที่ว่าง ประการที่สองมันสามารถลบออบเจกต์ได้ไม่เพียงแค่ตามดัชนี (เช่น อาร์เรย์ปกติ) แต่ยังสามารถลบออบเจกต์ได้ ด้วย :
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(lionel);

   System.out.println(cats.toString());
}
ผลลัพธ์: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] วิธีนี้สะดวกมากหากคุณไม่ต้องการติดตามดัชนีของวัตถุที่ต้องการตลอดเวลา ดูเหมือนว่าเราจะพบการลบตามปกติ ลองจินตนาการถึงสถานการณ์นี้: เราต้องการทำซ้ำรายการของเราและลบแมวที่มีชื่อเฉพาะ ในการทำเช่นนี้ เราจะใช้forการวนรอบแบบเร็ว (หรือที่เรียกว่า for-each loop) ซึ่งเราได้รับการแนะนำในบทเรียนของ Rishi:
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   for (Cat cat: cats) {

       if (cat.name.equals("Behemoth")) {
           cats.remove(cat);
       }
   }

   System.out.println(cats);
}
รหัสดูสมเหตุสมผลอย่างสมบูรณ์ แต่ผลลัพธ์อาจสร้างความประหลาดใจอย่างมาก: ข้อยกเว้นในเธรด "main" java.util.ConcurrentModificationException ที่ java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) ที่ java.util.ArrayList$Itr.next(ArrayList. java:831) ที่ Cat.main(Cat.java:25) มีข้อผิดพลาดบางอย่าง และไม่ชัดเจนว่าเหตุใดจึงเกิดขึ้น กระบวนการนี้เกี่ยวข้องกับความแตกต่างหลายประการที่ต้องได้รับการแก้ไข นี่คือกฎทั่วไปที่คุณต้องจำไว้: คุณไม่สามารถวนซ้ำคอลเลกชันและเปลี่ยนองค์ประกอบพร้อมกันได้ และเราหมายถึงการเปลี่ยนแปลงทุกประเภท ไม่ใช่แค่การกำจัดเท่านั้น หากคุณแทนที่การนำแมวออกด้วยการพยายามใส่แมวใหม่ ผลลัพธ์จะเหมือนเดิม:
for (Cat cat: cats) {

   cats.add(new Cat("Salem Saberhagen"));
}

System.out.println(cats);
ข้อยกเว้นในเธรด "main" java.util.ConcurrentModificationException ที่ java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) ที่ java.util.ArrayList$Itr.next(ArrayList.java:831) ที่ Cat.main( Cat.java:25) เราเปลี่ยนการดำเนินการหนึ่งเป็นอีกการดำเนินการหนึ่ง แต่ผลลัพธ์ไม่เปลี่ยนแปลง: เราได้รับ ConcurrentModificationExceptionเดียวกัน มันเกิดขึ้นเมื่อเราพยายามทำลายกฎด้านบนโดยเปลี่ยนรายการในขณะที่วนซ้ำ ใน Java เราต้องการวัตถุพิเศษที่เรียกว่าตัววนซ้ำ (Iteratorคลาส) เพื่อลบรายการในขณะที่วนซ้ำคอลเลกชัน ชั้นIteratorเรียนมีหน้าที่รับผิดชอบในการวนซ้ำรายการองค์ประกอบอย่างปลอดภัย มันค่อนข้างง่ายเนื่องจากมีเพียง 3 วิธี:
  • hasNext()- คืนค่าจริงหรือเท็จ ขึ้นอยู่กับว่ามีรายการถัดไปในรายการ หรือเราไปถึงรายการสุดท้ายแล้ว
  • next()- ส่งคืนรายการถัดไปในรายการ
  • remove()- ลบรายการออกจากรายการ
อย่างที่คุณเห็น iterator ได้รับการออกแบบมาเพื่อความต้องการของเรา และในขณะเดียวกันก็ไม่มีอะไรซับซ้อนเกี่ยวกับมัน สมมติว่าเราต้องการตรวจสอบว่ามีองค์ประกอบถัดไปในรายการของเราหรือไม่ และแสดงองค์ประกอบดังกล่าวหากมี:
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list

   Cat nextCat = catIterator.next();// Get the next element
   System.out.println(nextCat);// Display it
}
ผลลัพธ์: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} อย่างที่คุณเห็น พวกมันได้ใช้วิธีพิเศษใน การArrayListสร้าง ตัวทำซ้ำ: iterator(). นอกจากนี้ โปรดทราบว่าเมื่อเราสร้างตัววนซ้ำ เราจะระบุคลาสของออบเจกต์ที่จะใช้งานด้วย ( <Cat>) บรรทัดล่างคือ iterator จัดการงานดั้งเดิมของเราได้อย่างง่ายดาย ตัวอย่างเช่น ลบแมวชื่อ "Lionel Messi":
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list

   Cat nextCat = catIterator.next();// Get the next element
   if (nextCat.name.equals("Lionel Messi")) {
       catIterator.remove();// Delete the cat with the specified name
   }
}

System.out.println(cats);
ผลลัพธ์: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] คุณอาจสังเกตว่าเราไม่ได้ระบุดัชนีหรือชื่อในเมธอดของตัววนremove()ซ้ำ ! ตัววนซ้ำนั้นฉลาดกว่าที่ปรากฏ: remove()ลบองค์ประกอบสุดท้ายที่ส่งคืนโดยตัววนซ้ำ อย่างที่คุณเห็น มันทำในสิ่งที่เราต้องการ :) โดยหลักการแล้ว นี่คือทุกสิ่งที่คุณจำเป็นต้องรู้เกี่ยวกับการลบองค์ประกอบออกจากไฟล์ArrayList. เกือบทุกอย่าง ในบทเรียนต่อไป เราจะดูในคลาสนี้และดูว่าเกิดอะไรขึ้นที่นั่นระหว่างการเรียกเมธอดต่างๆ :) จนกว่าจะถึงตอนนั้น!
ความคิดเห็น
  • เป็นที่นิยม
  • ใหม่
  • เก่า
คุณต้องลงชื่อเข้าใช้เพื่อแสดงความคิดเห็น
หน้านี้ยังไม่มีความคิดเห็นใด ๆ