yangmillstheory
yangmillstheory

Reputation: 1065

Return reversed generic list-type in Java

I'm doing some exercises on generic programming; is there a way to take a class that implements List and return a reversed version of that same class? It seems this should be feasible as this, at least taking the term at face value, is "generic programming" writ large.

Maybe by performing an in-place reversal? I also considered Collections.reverse(), but it's a void method.

Here is my attempt and demo:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Arrays;

public class ReverseDemo {

public static <T> List<T> reverse(List<T> list) {
    List<T> reversed = new ArrayList<T>();

    for (int i = list.size() - 1; i >= 0; i--) {
        reversed.add(list.get(i));
      }

    return reversed;
}

public static void main(String[] args) {
    LinkedList<Integer> linkedInt = new LinkedList<Integer>();
    ArrayList<Double> arrayDouble = new ArrayList<Double>();

    for (int k = 0; k < 10; k++) {
        double doubleNum = 10*Math.random();
        int intNum = (int) (10*Math.random());
        linkedInt.add(intNum);
        arrayDouble.add(doubleNum);
    }

    // LinkedList<Integer> demo
    System.out.println(Arrays.toString(linkedInt.toArray()));
    System.out.println(Arrays.toString(reverse(linkedInt).toArray()));
    System.out.println(reverse(linkedInt) instanceof LinkedList<?>);  // false

    // ArrayList<Double> demo
System.out.println(Arrays.toString(arrayDouble.toArray()));        
System.out.println(Arrays.toString(reverse(arrayDouble).toArray()));          
System.out.println(reverse(arrayDouble) instanceof ArrayList<?>);  // true
}
}

Incidentally this is my first post here, does anyone know the best way to post code directly from Eclipse while preserving the spacing and indentation therefrom? I've used the four-spaces method specified here, but it's a bit inconsistent.

Upvotes: 5

Views: 3657

Answers (7)

yangmillstheory
yangmillstheory

Reputation: 1065

Thanks for the replies everyone. I wrote a method reverse2 which works at least for implementing classes ArrayList and LinkedList. Not sure how efficient it is.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Arrays;

// See http://stackoverflow.com/questions/16799066/return-reversed-generic-list-type-in-java.
public class ReverseDemo {

    public static <T> List<T> reverse1(List<T> list) {
        List<T> reversed = new ArrayList<T>();

        for (int i = list.size() - 1; i > -1; i--) {
            reversed.add(list.get(i));
          }

        return reversed;
    }

    public static <T> List<T> reverse2(List<T> list) {
        int size = list.size();

        ArrayList<T> obArray = new ArrayList<T>();
        obArray.addAll(list);

        ListIterator<T> iter = list.listIterator();  
        for (int i = 0; i < size; i++) {
            iter.next();
            iter.set(obArray.get(size - 1 - i));
        }       

        return list;
    }

    public static void main(String[] args) {
        LinkedList<Integer> linkedInt = new LinkedList<Integer>();
        ArrayList<Double> arrayDouble = new ArrayList<Double>();

        for (int k = 0; k < 10; k++) {
            double doubleNum = 10*Math.random();
            int intNum = (int) (10*Math.random());
            linkedInt.add(intNum);
            arrayDouble.add(doubleNum);
        }

        TextIO.putln("Testing reverse1.");

        // LinkedList<Integer> demo
        System.out.println(Arrays.toString(linkedInt.toArray()));
        System.out.println(Arrays.toString(reverse1(linkedInt).toArray()));
        TextIO.putln("LinkedList structure preserved?");
        System.out.println(reverse1(linkedInt) instanceof LinkedList<?>);

        // ArrayList<Double> demo
        System.out.println(Arrays.toString(arrayDouble.toArray()));
        System.out.println(Arrays.toString(reverse1(arrayDouble).toArray()));
        TextIO.putln("ArrayList structure preserved?");
        System.out.println(reverse1(arrayDouble) instanceof ArrayList<?>);

        TextIO.putln("\nTesting reverse2.");

        // LinkedList<Integer> demo
        System.out.println(Arrays.toString(linkedInt.toArray()));
        System.out.println(Arrays.toString(reverse2(linkedInt).toArray()));
        TextIO.putln("LinkedList structure preserved?");
        System.out.println(reverse2(linkedInt) instanceof LinkedList<?>);

        // ArrayList<Double> demo
        System.out.println(Arrays.toString(arrayDouble.toArray()));
        System.out.println(Arrays.toString(reverse2(arrayDouble).toArray()));
        TextIO.putln("ArrayList structure preserved?");
        System.out.println(reverse2(arrayDouble) instanceof ArrayList<?>);
    }

}

console output:

Testing reverse1. [8, 0, 1, 9, 3, 4, 3, 7, 6, 3] [3, 6, 7, 3, 4, 3, 9, 1, 0, 8] LinkedList structure preserved? false [8.301783107294664, 5.434068303620735, 9.095396759542615, 0.41823972682620836, 9.56659902304762, 3.2560723280079085, 4.037362000077436, 9.731919590391389, 0.5243645318825874, 5.9432185528462975] [5.9432185528462975, 0.5243645318825874, 9.731919590391389, 4.037362000077436, 3.2560723280079085, 9.56659902304762, 0.41823972682620836, 9.095396759542615, 5.434068303620735, 8.301783107294664] ArrayList structure preserved? true

Testing reverse2. [8, 0, 1, 9, 3, 4, 3, 7, 6, 3] [3, 6, 7, 3, 4, 3, 9, 1, 0, 8] LinkedList structure preserved? true [8.301783107294664, 5.434068303620735, 9.095396759542615, 0.41823972682620836, 9.56659902304762, 3.2560723280079085, 4.037362000077436, 9.731919590391389, 0.5243645318825874, 5.9432185528462975] [5.9432185528462975, 0.5243645318825874, 9.731919590391389, 4.037362000077436, 3.2560723280079085, 9.56659902304762, 0.41823972682620836, 9.095396759542615, 5.434068303620735, 8.301783107294664] ArrayList structure preserved? true

Upvotes: 0

splungebob
splungebob

Reputation: 5415

This seems to work:

import java.util.*;

public class ReverseListDemo
{
  public static void main(String[] args)
  {
    List<String> original = Arrays.asList("A", "B", "C");
    List<String> reversal = reverse(original);

    System.out.println("Original: " + original);
    System.out.println("Reversal: " + reversal);
  }

  public static <T> List<T> reverse(List<T> list)
  {
    T[] objects = (T[]) list.toArray();
    List<T> copy = Arrays.asList(objects);
    Collections.reverse(copy);
    return copy;
  }
}

Upvotes: 0

dev2d
dev2d

Reputation: 4262

try following

public static <T> List<T> reverse(List<T> list) {

    List<T> reversed=null;
    try {
        reversed = list.getClass().newInstance();
        Collections.reverse(list);
        reversed.addAll(list);

    } catch (InstantiationException | IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    };

     return reversed;
}

Upvotes: 2

debaser
debaser

Reputation: 109

The Guava library has a nice, non-destructive solution to the problem. See Lists.reverse(List).

They define a suite of ReverseList classes that wrap the input List. From there, it's just a matter of translating all of calls (although "just" might be understating things a bit).

Upvotes: 3

gpeche
gpeche

Reputation: 22504

If you want to preserve the original list, you can try using:

originalList.getClass().newInstance()

That is not a 100% correct solution as it may throw if the original class does not have a default constructor. However, most collections have default constructors that create empty instances.

Upvotes: 2

Marko Topolnik
Marko Topolnik

Reputation: 200148

All java.util implementations of List are cloneable, so you could use that, but sadly not without resorting to reflection. While on the reflection chapter, you may also use the copy-constructor, which is also sported by all Java's collections.

There is no fully general approach to non-destructive reversing, unfortunately.

Destructive reversing, on the other hand, is too trivial to be interesting.

Upvotes: 1

greedybuddha
greedybuddha

Reputation: 7507

The Collections.reverse() might be void, but that's only because you should be passing in the List to be reversed.

List<T> myList = ...;
Collections.reverse(myList);

You now have a reversed list.

Upvotes: 1

Related Questions