views:

421

answers:

3

So, this is an efficiency question.

I have two collections - an ArrayList and a Stack. I use the stack because I needed some simple pop/push functionality for this bit of code. The ArrayList is essentially the out variable as this is a small section of code in the function.

So, I the variables are defined as such, then code is run to add elements to the stack.

ArrayList<String> out = new ArrayList<String>();

/* other code.. */

Stack<String> lineStack = new Stack<String>();

/* code that adds stuff to the stack */

The question is, now that I have a fully populated stack, how do I place it in the out ArrayList in a reverse order then from the pop order.

My first thought up solution was

 while(!lineStack.empty()) {
     out.add(0, lineStack.pop());
 }

...which works, but I worry about the efficiency of adding an element to the beginning of the ArrayList (which forces all existing elements to need to shift.. it's a linked list (I believe).. big deal.. but still a concern). Also, I am running this through a loop... perhaps unnecessarily.

So, my second solution that didn't involve looping (at least in my code, i'm sure the back end calls are doing it).

 List l = lineStack.subList(0, lineStack.size());
 out.addAll(l);

I know I don't need to allocate the list, but it'll keep for cleaner code. However, I am not sure if this will give me a particularly helpful performance gain.

So, my question is: Which of these will likely be most efficient for SMALL to MEDIUM size sets? If there is a more efficient solution, what would it be?

A: 

Subclass the ArrayList and add a pop and push method. Use this as the Stack class.

When you are ready, assign it to an Arraylist variable and you're ready

Toad
+7  A: 

The Iterable<T> implementation order of Stack<T> goes in the order you want anyway, so you can just use

new ArrayList<String>(stack);

Here's a short but complete example:

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        Stack<String> stack = new Stack<String>();
        stack.push("Bottom");
        stack.push("Middle");
        stack.push("Top");

        List<String> list = new ArrayList<String>(stack);

        for (String x : list)
        {
            System.out.println(x);
        }
    }
}

This prints out:

Bottom
Middle
Top

(which is the opposite order to what you'd get if you popped them).

EDIT: One other question - do you really need it in an ArrayList<String> anyway? Stack<T> implements List<T>; what special features of ArrayList do you need? (I'm not saying you don't need them, just checking!)

Jon Skeet
You made a very good point!I can't reinitialize the ArrayList (not guaranteed to be empty), but since the Iterator is going to give it to me in the right order, I can just out.addAll(lineStack); .. I don't know why I bothered making it into a list. *facepalm*Thanks!
Dave Morgan
+1 awesome, at least compared to my answer :)
dfa
To the edit: Aye. The ArrayList is being used elsewhere and is part of the API - Can't really change it :(.
Dave Morgan
That's absolutely fair enough. I'll leave the edit in for posterity, just in case anyone else finds themselves in a similar situation but where they *could* just use the stack :)
Jon Skeet
A: 

making use of Stack.toArray is simple:

@Test
public void stackToList() {
    Stack<String> stack = new Stack<String>();
    stack.push("aaa");
    stack.push("bbb");
    stack.push("ccc");
    List<String> list=  Arrays.asList(stack.toArray(new String[0]));
    Assert.assertEquals(Arrays.asList("aaa", "bbb", "ccc"), list);
}
dfa