Reversing a Queue<Integer> and converting it into an int array

Viewed 4150

I have a Queue<Integer> declared as Queue<Integer> queue=new LinkedList();, I need to reverse the elments order in it, and then convert it into an int array. I wrote below code:

Collections.reverse((List)queue);
int[] res=queue.stream().mapToInt(Integer::intValue).toArray();

This code has two problems:

  1. the explict casting (List)queue;
  2. I wonder if there is a one line solution.

So do we have any more elegant way to do this?


Clearification of the problem:

Whether the queue is reversed is not important. An int array of the reversed elements is what I need.

9 Answers

First, please don't use raw types (do use the diamond operator). Not quite a one liner, but you could first convert to an int[] and then use commons lang ArrayUtils.reverse(int[]) like

Queue<Integer> queue = new LinkedList<>();
// ...
int[] arr = queue.stream().mapToInt(Integer::intValue).toArray();
ArrayUtils.reverse(arr);

You could also write your own int[] reverse method that allowed for a fluent interface (e.g. return the int[]) then you could make it a one liner. Like,

public static int[] reverse(int[] arr) {
    for (int i = 0; i < arr.length / 2; i++) {
        int temp = arr[i];
        arr[i] = arr[arr.length - i - 1];
        arr[arr.length - i - 1] = temp;
    }
    return arr;
}

And then

int[] arr = reverse(queue.stream().mapToInt(Integer::intValue).toArray());

No need to get fancy here.

static int[] toReversedArray(Queue<Integer> queue) {
    int i = queue.size();
    int[] array = new int[i];
    for (int element : queue) {
        array[--i] = element;
    }
    return array;
}

Not a one-liner, but easy to read and fast.

The Collections.reverse implies only to List which is just one type of Collection, you cannot cast a Queue to a List. But you can try casting it to a LinkedList as:

Collections.reverse((LinkedList)queue);

Details:

I doubt that there is a built-in API for reversing the queue. You could still follow a conventional way of doing that using a Stack as :

Stack<Integer> stack = new Stack<>();
while (!queue.isEmpty()) {
    stack.add(queue.remove());
}
while (!stack.isEmpty()) {
    queue.add(stack.pop());
}

and then convert to an array as you will

int[] res = queue.stream().mapToInt(Integer::intValue).toArray();

On the other hand, if a Deque satisfies your needs currently, you can simply rely on the LinkedList itself since it implements a Deque as well. Then your current implementation would be as simple as :

LinkedList<Integer> dequeue = new LinkedList<>();
Collections.reverse(dequeue);
int[] res = dequeue.stream().mapToInt(Integer::intValue).toArray();

whether the queue is reversed is not important. An int array of the reversed elements is what I need.

Another solution from what others have already suggested is to reverse the Stream of the queue and then mapToInt to convert to an array as :

Queue<Integer> queue = new LinkedList<>();
int[] res = reverse(queue.stream()).mapToInt(Integer::intValue).toArray();

This uses a utility reverse suggested by Stuart Marks in this answer such that:

@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
    Object[] temp = input.toArray();
    return (Stream<T>) IntStream.range(0, temp.length)
            .mapToObj(i -> temp[temp.length - i - 1]);
}

In Java8 version you can use Stream API to help you.

The skeleton of code like this:

int[] reversedQueue = queue.stream()
    .collect(Collector.of(() -> new ArrayDeque<Integer>(), ArrayDeque::addFirst, (a,b)->a))
    .stream().mapToInt(Integer::intValue).toArray();

Finally, I figure out this one line solution.

Integer[] intArray = queue.stream()
            .collect(LinkedList::new, LinkedList::addFirst, LinkedList::addAll)
            .toArray(new Integer[queue.size()]);

the int[] version should like

int[] intArray = queue.stream()
            .collect(LinkedList<Integer>::new, LinkedList::addFirst, LinkedList::addAll)
            .stream()
            .mapToInt(Integer::intValue)
            .toArray();

You can use the LazyIterate utility from Eclipse Collections as follows.

int[] res = LazyIterate.adapt(queue)
        .collectInt(i -> i)
        .toList()
        .asReversed()
        .toArray();

You can also use the Collectors2 class with a Java Stream.

int[] ints = queue.stream()
        .collect(Collectors2.collectInt(i -> i, IntLists.mutable::empty))
        .asReversed()
        .toArray();

You can stream the int values directly into a MutableIntList, reverse it, and then convert it to an int array.

int[] ints =
    IntLists.mutable.ofAll(queue.stream().mapToInt(i -> i)).asReversed().toArray();

Finally, you can stream the int values directly into a MutableIntStack and convert it to an int array.

int[] ints =
    IntStacks.mutable.ofAll(queue.stream().mapToInt(i -> i)).toArray();

Note: I am a committer for Eclipse Collections.

This is one line, but it may not be very efficient:

int[] res = queue.stream()
                 .collect(LinkedList<Integer>::new, (l, e) -> l.addFirst(e), (l1, l2) -> l1.addAll(l2))
                 .stream()
                 .mapToInt(Integer::intValue)
                 .toArray();

If you want to be efficient and readable, you should continue using what you have now.

Here is a different solution using Stream and Collections.reverse() in one line of code:

Integer[] reversedArray = queue.stream()
        .collect(Collectors.collectingAndThen(Collectors.toList(),
                list -> {
                    Collections.reverse(list);
                    return list.toArray(new Integer[0]);
                }
        ));

OR

int[] reversedArray = queue.stream()
        .collect(Collectors.collectingAndThen(Collectors.toList(),
                list -> {
                    Collections.reverse(list);
                    return list.stream()
                            .mapToInt(Integer::intValue)
                            .toArray();
                }
        ));

Here's a way that creates a reversed array without reversing the queue:

int[] i = { queue.size() };
int[] array = new int[i[0]];
queue.forEach(n -> array[--i[0]] = n);

The above code is quite hacky due to the impossibility to modify local variables from within lambda expressions. So here i needs to be a one-element array, to overcome this restriction.

Note: bear in mind that I've come to this solution just for fun :)

Related