วิธีรับมุมมองรายการแบบย้อนกลับในรายการใน Java


214

ฉันต้องการให้มีมุมมองรายการแบบย้อนกลับในรายการ (ในลักษณะที่คล้ายกันกว่าList#sublistให้มุมมองรายการย่อยในรายการ) มีฟังก์ชั่นที่ให้ฟังก์ชั่นนี้บ้าง?

ฉันไม่ต้องการทำสำเนารายการหรือแก้ไขรายการ

มันจะเพียงพอถ้าฉันได้อย่างน้อย iterator กลับรายการในกรณีนี้แม้ว่า


นอกจากนี้ฉันรู้วิธีที่จะใช้ตัวเอง ฉันแค่ถามว่า Java ให้อะไรเช่นนี้แล้ว

การสาธิตการใช้งาน:

static <T> Iterable<T> iterableReverseList(final List<T> l) {
    return new Iterable<T>() {
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                ListIterator<T> listIter = l.listIterator(l.size());                    
                public boolean hasNext() { return listIter.hasPrevious(); }
                public T next() { return listIter.previous(); }
                public void remove() { listIter.remove(); }                 
            };
        }
    };
}

ฉันเพิ่งพบว่าListการใช้งานบางอย่างมีdescendingIterator()ซึ่งเป็นสิ่งที่ฉันต้องการ Listแม้ว่าจะไม่มีการดำเนินการดังกล่าวทั่วไป ซึ่งเป็นชนิดของแปลกเพราะการดำเนินการที่ผมได้เห็นในก็พอโดยทั่วไปในการทำงานใด ๆLinkedListList


1
คุณสามารถสร้างรายการตามลำดับย้อนกลับได้หรือไม่
Tony Ennis

ใช่แล้ว - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/
......

หากคุณเยี่ยมชมลิงค์นี้เพื่อค้นหาคำตอบวิธีการย้อนกลับ (แก้ไข) รายการนี่คือคำตอบ:Collections.reverse(list)
ZhaoGang

คำตอบ:


210

Guavaให้สิ่งนี้: Lists.reverse (รายการ)

List<String> letters = ImmutableList.of("a", "b", "c");
List<String> reverseView = Lists.reverse(letters); 
System.out.println(reverseView); // [c, b, a]

ซึ่งแตกต่างจากCollections.reverseนี้เป็นมุมมองอย่างแท้จริง... มันไม่ได้เปลี่ยนการเรียงลำดับขององค์ประกอบในรายการเดิม นอกจากนี้ด้วยรายการต้นฉบับที่แก้ไขได้การเปลี่ยนแปลงทั้งรายการดั้งเดิมและมุมมองจะปรากฏในอีกรายการหนึ่ง


11
ปัญหาคือฝรั่งเป็นห้องสมุดที่มีขนาดใหญ่มาก ดูการอภิปราย: github.com/google/guava/issues/1954และcode.google.com/p/guava-l ไลบรารี/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito: ProGuard ยังคงเป็นทางออกที่ดีที่สุดสำหรับขนาดห้องสมุดแม้ว่าจะมีการปรับปรุงที่เราสามารถทำได้ ไม่ว่าในกรณีใดฉันไม่คิดว่าขนาดห้องสมุดมีความเกี่ยวข้องกับคำตอบนี้
ColinD

2
ใช่ขนาดห้องสมุดไม่เกี่ยวข้องกับคำตอบนี้ แต่มีความเกี่ยวข้องที่จะได้รับแจ้งสำหรับโปรแกรมเมอร์ (ดังนั้นฉันแสดงความคิดเห็น)! ขอบคุณมากสำหรับห้องสมุดที่ยอดเยี่ยมนี้และสำหรับคำแนะนำของคุณ @ColinD!
Filipe Brito

@ ColinD, yup มันเป็นความผิดพลาดของฉัน เพื่อนร่วมงานเพิ่ม google-collection ซึ่งมีเนมสเปซและคลาสเดียวกัน ( List) แต่ไม่มีเมธอดย้อนกลับ การลบมันทำให้ฝรั่งสามารถใช้งานได้อีกครั้ง
AaA

นักพัฒนาไม่สามารถควบคุมว่าจะใช้ไลบรารีใดได้ตลอดเวลาและการเพิ่มห้องสมุดใหม่ทั้งหมดเพื่อให้ง่ายขึ้นดูเหมือนว่า overkill - โดยเฉพาะอย่างยิ่งเมื่อปัญหาสามารถแก้ไขได้ListIterator.previous()
Jonathan Benn

218

ใช้วิธี. clone () ในรายการของคุณ มันจะส่งคืนสำเนาตื้นซึ่งหมายความว่ามันจะมีตัวชี้ไปยังวัตถุเดียวกันดังนั้นคุณจะไม่ต้องคัดลอกรายการ จากนั้นก็ใช้ Collections

Ergo,

Collections.reverse(list.clone());

หากคุณใช้Listและไม่มีสิทธิ์เข้าถึงclone()คุณสามารถใช้subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);

21
clone()โดยปกติจะสร้างสำเนาของรายการ อย่างไรก็ตามList#clone()ยังไม่มีอยู่
อัลเบิร์

6
คุณมีสิทธิ์ทางเทคนิคส่วนต่อประสานรายการนั้นไม่มีวิธีการโคลน () แต่ ArrayList, LinkedList และ Vector ล้วน แต่ทำ
jcalvert

2
clone()ฉันเพียงแค่เงยหน้าขึ้นมองการดำเนินงานของ มันทำสำเนาเต็มของรายการ (มันไม่ได้คัดลอกแต่ละวัตถุเดียวในรายการ แต่นั่นไม่ใช่สิ่งที่ฉันพูดถึง)
อัลเบิร์

21
โปรดทราบว่า Collections.reverse ส่งกลับเป็นโมฆะดังนั้นคุณจะสูญเสียการอ้างอิงโคลน คุณต้องกำหนดโคลนให้กับตัวแปรก่อนจากนั้นจึงจัดเรียง
user12722

10
subListไม่ได้คัดลอกมันเป็นเพียงแค่ให้มุมมองในรายการพื้นฐานดังนั้นการย้อนกลับมุมมองนี้จะกลับรายการพื้นฐาน
Roland

80

ถ้าฉันเข้าใจถูกต้องมันเป็นหนึ่งบรรทัดของรหัสมันเหมาะกับฉัน

 Collections.reverse(yourList);

12
นั่นไม่ใช่มุมมองรายการ ที่ปรับเปลี่ยนรายการ
อัลเบิร์ต

35

มันไม่หรูหราอย่างแน่นอน แต่ถ้าคุณใช้ List.listIterator (ดัชนีอินเด็กซ์) คุณสามารถรับ ListIterator แบบสองทิศทางได้ที่ท้ายรายการ:

//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());

while (li.hasPrevious()) {
   String curr = li.previous()
}

1
นี่เป็นคำตอบที่ดีที่สุดเนื่องจาก (1) ไม่จำเป็นต้องมีไลบรารีและ (2) ไม่ได้แก้ไขรายการดั้งเดิมตามที่ OP ร้องขอ
Jonathan Benn

12

Collections.reverse (nums) ... จริง ๆ แล้วมันกลับคำสั่งขององค์ประกอบ รหัสด้านล่างควรจะชื่นชมมาก -

List<Integer> nums = new ArrayList<Integer>();
nums.add(61);
nums.add(42);
nums.add(83);
nums.add(94);
nums.add(15);
//Tosort the collections uncomment the below line
//Collections.sort(nums); 

Collections.reverse(nums);

System.out.println(nums);

เอาท์พุท: 15,94,83,42,61


8
คุณแค่ทำซ้ำคำตอบที่คนอื่นเขียนเมื่อ 6 ปีก่อน
Jonathan Benn

1
... และไม่ใช่มุมมอง สิ่งนี้จะปิดรายการ
Jason S

6

java.util.DequeมีdescendingIterator()- หากคุณListเป็นDequeคุณสามารถใช้สิ่งนั้นได้


หากคุณไม่ต้องการใช้วิธี descndingIterator () ในตัวดูเหมือนว่าการใช้ ConcurrentLinkedDeque น่าจะดีที่สุดที่จะกลับรายการที่มีขนาดใหญ่มาก? โดยทั่วไปเพียงแค่คัดลอกจากหนึ่งสำรับไปที่สำรับใหม่โดยใช้แบบสำรวจแล้วเสนอ Sorta เหมือนมีไพ่สำรับแล้วนำแต่ละอันขึ้นด้านบนลงในกองใหม่ตามลำดับ
djangofan

4

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่วันนี้ฉันกำลังมองหาบางอย่างเช่นนี้ ในที่สุดฉันก็เขียนโค้ดเอง:

private List reverseList(List myList) {
    List invertedList = new ArrayList();
    for (int i = myList.size() - 1; i >= 0; i--) {
        invertedList.add(myList.get(i));
    }
    return invertedList;
}

ไม่แนะนำสำหรับรายการแบบยาวสิ่งนี้ไม่เหมาะสำหรับทุกคน เป็นวิธีแก้ปัญหาที่ง่ายสำหรับสถานการณ์ควบคุม (รายการที่ฉันจัดการมีองค์ประกอบไม่เกิน 100 รายการ)

หวังว่าจะช่วยใครซักคน


2
รหัสของคุณมีปัญหาหนึ่ง - คุณสามารถใส่รายการใด ๆ ไปได้ แต่มันจะส่งคืน ArrayList (เป็นรายการ) เสมอ และถ้าฉันต้องการ LinkedList ล่ะ ดีกว่าที่จะแก้ไข myList และส่งคืนโมฆะ
Dmitry Zaytsev

2
โปรดทราบว่านี่ไม่ใช่สิ่งที่ฉันขอ ฉันขอพร็อกซี / มุมมองบางประเภทไม่ใช่สำเนา
อัลเบิร์

4

ฉันใช้สิ่งนี้:

public class ReversedView<E> extends AbstractList<E>{

    public static <E> List<E> of(List<E> list) {
        return new ReversedView<>(list);
    }

    private final List<E> backingList;

    private ReversedView(List<E> backingList){
        this.backingList = backingList;
    }

    @Override
    public E get(int i) {
        return backingList.get(backingList.size()-i-1);
    }

    @Override
    public int size() {
        return backingList.size();
    }

}

แบบนี้:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list

1

คุณยังสามารถทำสิ่งนี้:

static ArrayList<String> reverseReturn(ArrayList<String> alist)
{
   if(alist==null || alist.isEmpty())
   { 
       return null;
   }

   ArrayList<String> rlist = new ArrayList<>(alist);

   Collections.reverse(rlist);
   return rlist;
}

5
นั่นไม่ใช่มุมมองรายการ มุมมองตรงกันข้ามกับสำเนา
อัลเบิร์ต

รายการย้อนกลับของรายการว่างเปล่าเป็นโมฆะ ??
ShellFish

1

คุณสามารถสลับตำแหน่งเมื่อคุณขอวัตถุ:

Object obj = list.get(list.size() - 1 - position);

1

สำหรับรายการขนาดเล็กเราสามารถสร้างLinkedListและใช้ประโยชน์จาก iterator จากมากไปน้อยดังนี้

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
         .descendingIterator().
         forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three

-3

ใช้reverse(...)วิธีการjava.util.Collectionsเรียน ผ่านรายการของคุณเป็นพารามิเตอร์และรายชื่อของคุณจะถูกกลับรายการ

Collections.reverse(list);

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