การกลับรายการใน Java - ในสถานที่และนอกสถานที่

ในบทช่วยสอนสั้นๆ นี้ คุณจะได้เรียนรู้วิธีกลับรายการแบบแทนที่รายการแทนที่ใน Java

การย้อนกลับในสถานที่และนอกสถานที่

เมื่อดำเนินการกับรายการ – คุณอาจต้องการพิจารณาว่าการดำเนินการนั้นเสร็จสิ้นแล้วหรือไม่ (การเปลี่ยนแปลงมีผลกับวัตถุดั้งเดิม) หรือว่าไม่อยู่ในตำแหน่ง (การเปลี่ยนแปลงมีผลกับสำเนาและต้นฉบับ วัตถุไม่เปลี่ยนแปลง)

บางภาษาและไลบรารีต้องการพฤติกรรมเริ่มต้นที่แตกต่างกัน ใน Java การดำเนินการส่วนใหญ่ในรายการย้อนกลับจะเป็น ในสถานที่.

หากนี่เป็นพฤติกรรมที่คุณต้องการ – เยี่ยมมาก! ถ้าไม่เช่นนั้น คุณจะต้องสร้างสำเนาของรายการก่อนที่จะย้อนกลับสำเนา:

List list = new ArrayList(Arrays.asList(1, 2, 3));
List listCopy = new ArrayList(list);

หมายเหตุ พื้นที่ clone() วิธี ไม่ได้ สร้างสำเนาลึก การสร้างรายการโดยใช้ new ArrayList(list) ไม่ได้ สร้างสำเนาลึก การสร้างสำเนาในเชิงลึกเป็นสิ่งที่ไม่ควรทำ และทำได้ยากอย่างน่าประหลาดใจในลักษณะทั่วไป (และไม่สมเหตุสมผลในบางกรณี ขึ้นอยู่กับประเภทข้อมูลในรายการ) สิ่งนี้จะไม่หยุดคุณไม่สามารถย้อนกลับได้ list และ ไม่ มีองค์ประกอบของ listCopy ถูกย้อนกลับแม้ว่า

คอลเลกชันย้อนกลับ ()

พื้นที่ Collections.reverse() วิธีเป็นวิธีมาตรฐานในการย้อนกลับของคอลเลกชันและทำหน้าที่เป็น "หายไป" List.reverse() กระบวนการ. มันกลับรายการในสถานที่:

List list = new ArrayList(Arrays.asList(1, 2, 3));
List listCopy = new ArrayList(list);

Collections.reverse(list);

System.out.println(list);     
System.out.println(listCopy); 

รายการฝรั่ง.ย้อนกลับ(รายการ)

หากคุณใช้ Google Guava ในโครงการอยู่แล้ว คุณยังสามารถใช้ประโยชน์จาก Lists คลาสซึ่งให้ reverse() เมธอด ซึ่งไม่เรียงลำดับรายการดั้งเดิมแบบแทนที่ แต่สร้างสำเนาและย้อนกลับสำเนา:

List list = new ArrayList(Arrays.asList(1, 2, 3));
List reversedList = Lists.reverse(list);

System.out.println(list);         
System.out.println(reversedList); 

หากคุณยังไม่มี คุณสามารถเพิ่ม Google Guava ในโครงการของคุณโดยใช้ Maven โดยรวมการพึ่งพาใน pom.xml ไฟล์:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
</dependency>

หรือผ่าน Gradle:

implementation group: 'com.google.guava', name: 'guava'

หมายเหตุ หากคุณยังไม่มี Google Guava หรือไม่ต้องการใช้สำหรับส่วนอื่นๆ ของโปรเจ็กต์ของคุณ อย่านำเข้ามาเพื่อการดำเนินการนี้เพียงอย่างเดียว และยึดตาม Collections.reverse() กระบวนการ. ฝรั่งเป็นที่พึ่งพาอาศัยกันมาก และเป็นการ overkill ที่สำคัญสำหรับการดำเนินการนี้เท่านั้น

List.add() และ List.remove()

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


public static int process(int input) {
    return input;
}

List list = new ArrayList(Arrays.asList(1, 2, 3));

for (int i = 0, j = list.size()-1; i <= j; i++) {
    int lastValue = process(list.remove(j));
    list.add(i, lastValue);
}

System.out.println(list);  

มาตรฐาน

แล้วอันไหนเร็วที่สุด? นอกจากนี้ยังขึ้นอยู่กับว่าคุณต้องการดำเนินการในสถานที่หรือนอกสถานที่

เกณฑ์มาตรฐานการกลับรายการในสถานที่

มาเปรียบเทียบทั้งสองแนวทางกับทั้งสามวิธีกัน โดยเริ่มจากนอกสถานที่:

List list = new Random().ints(100, 1, 11)
                .boxed()
                .collect(Collectors.toList());

int runs = 1000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    reverseListCollections(list);
}
long end1 = System.currentTimeMillis();
System.out.println(String.format("Collections.reverse() took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    reverseListGuava(list);
}
long end2 = System.currentTimeMillis();
System.out.println(String.format("Guava's Lists.reverse() took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    reverseListManually(list);
}
long end3 = System.currentTimeMillis();
System.out.println(String.format("Manually took: %s miliseconds", end3-start3));

System.out.println("Original list: " + list);

ผลลัพธ์นี้ใน:

Collections.reverse() took: 3 miliseconds
Guava's Lists.reverse() took: 4 miliseconds
Manually took: 13 miliseconds
Original list: [6, 7, 9, 7, 2, 5, 4, 1, 3, 2, 2, 6, ...

ดูคู่มือเชิงปฏิบัติสำหรับการเรียนรู้ Git ที่มีแนวทางปฏิบัติที่ดีที่สุด มาตรฐานที่ยอมรับในอุตสาหกรรม และเอกสารสรุปรวม หยุดคำสั่ง Googling Git และจริงๆ แล้ว เรียน มัน!

จะเกิดอะไรขึ้นเมื่อเราเพิ่มจำนวนองค์ประกอบจาก 100 เป็น 1000

Collections.reverse() took: 9 miliseconds
Guava's Lists.reverse() took: 4 miliseconds
Manually took: 133 miliseconds
Original list: [10, 2, 2, 6, 2, 4, 7, 3, 9, 2, 7, 5, ...

ฝรั่งยังคงเครื่องหมาย 4ms! วิธีการแบบแมนนวลมีความซับซ้อนด้านเวลาที่เลวร้ายที่สุด และเพิ่มขึ้นเป็นเส้นตรง Collections.reverse() ทนทุกข์ทรมานน้อยลงจากการขยายขนาด แต่การนำของฝรั่งไปปฏิบัติได้รับความทุกข์น้อยที่สุด แม้ว่า โปรดจำไว้ว่า เราไม่ได้คัดลอกรายการสำหรับแนวทางฝรั่งด้วยตนเอง เกณฑ์มาตรฐานจะเปลี่ยนไปเมื่อเราละทิ้งแนวคิดที่จะมีรายการ "ดั้งเดิม" และ "ย้อนกลับ" หรือไม่

เกณฑ์มาตรฐานการกลับรายการนอกสถานที่

ด้วยองค์ประกอบ 1000 รายการและแต่ละรายการทำงานบนสำเนารายการที่ไม่ย้อนกลับ (ซึ่งไม่รวมอยู่ในการวัดเวลา) เมื่อเราลบสำเนาด้วยตนเองออกจากแต่ละวิธีและเรียกใช้รหัสอีกครั้ง:

Collections.reverse() took: 7 miliseconds
Guava's Lists.reverse() took: 3 miliseconds
Manually took: 131 miliseconds
Original list: [6, 8, 10, 7, 3, 8, 7, 1, 1, 9, 5, ...

ฝรั่ง ยังคง มีประสิทธิภาพเหนือกว่าทั้งคู่อย่างต่อเนื่อง Collections.reverse() และแนวทางแบบแมนนวล

สรุป

ในคู่มือฉบับย่อนี้ คุณได้เรียนรู้วิธีย้อนกลับรายการใน Java ทั้งแบบแทนที่และไม่อยู่ในตำแหน่ง เพื่อรักษารายการเดิมไว้ไม่ให้ทำงาน เราใช้ Collections.reverse() วิธีการ, Google Guava's Lists.reverse() วิธีการและแนวทางด้วยตนเอง

ประทับเวลา:

เพิ่มเติมจาก สแต็ค