Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy list shift and unshift

Tags:

list

groovy

Is there really no built-in way to 'shift' and 'unshift' with lists in groovy? (something that ruby, javascript have) For instance:

def list = [1,2,3,4,5]
firstElement = list.shift
println firstElement          // 1
println list                  // [2,3,4,5]

list.unshift 1
println list                  // [1,2,3,4,5]

If no built in way, are there conventional alternatives?

like image 260
Roy Truelove Avatar asked Mar 17 '14 14:03

Roy Truelove


3 Answers

There's no built in shift and unshift... Here are some options:

You could use a queue:

def queue = [ 1, 2, 3, 4, 5 ] as Queue

def firstElement = queue.poll()

assert firstElement == 1
assert queue == [ 2, 3, 4, 5 ]

But adding back in with offer adds to the wrong end, so use offerFirst:

queue.offerFirst( 1 )
assert queue == [ 1, 2, 3, 4, 5 ]

Or you could use a Stack, but you'd need to reverse your list to get 1 as the first element off of it.

def stack = [ 1, 2, 3, 4, 5 ].reverse() as Stack

def firstElement = stack.pop()

assert firstElement == 1
assert stack == [ 5, 4, 3, 2 ]

stack.push( 1 )
assert stack == [ 5, 4, 3, 2, 1 ]

Or, you could go the long way round:

def list = [ 1, 2, 3, 4, 5 ]

(firstElement, list) = [ list.head(), list.tail() ]

assert firstElement == 1
assert list == [ 2, 3, 4, 5 ]

list.add( 0, 1 )
assert list == [ 1, 2, 3, 4, 5 ]

Or you could add shift and unshift to the metaClass of List:

List.metaClass.shift = {
    delegate.remove( 0 )
}
List.metaClass.unshift = { val ->
    delegate.add( 0, val )
    delegate
}

def list = [ 1, 2, 3, 4, 5 ]
def firstElement = list.shift()
assert firstElement == 1
assert list == [ 2, 3, 4, 5 ]

list.unshift( 1 )
assert list == [ 1, 2, 3, 4, 5 ]
like image 108
tim_yates Avatar answered Nov 16 '22 12:11

tim_yates


JRE methods List.remove(int) and List.add(int, E) are supersets of shift and unshift operations, making this trivial for groovy. No reason to involve other classes as other people are proposing.

def baseList = ['one', 'two', 'three']

// Unshift operation:
baseList.add(0, 'zero')
assert  ['zero', 'one', 'two', 'three'] == baseList

// Shift operation
assert  'zero' == baseList.remove(0)
assert  ['one', 'two', 'three'] == baseList

(dummy text to satisfy stackoverflow edit)

like image 23
Blaine Avatar answered Nov 16 '22 11:11

Blaine


If you need to add and remove from the front, you may want to use an implementation of a Java Deque for your lists. This data structure specifically allows efficient additions and removals from either end.

It has methods push() and pop() for adding and removing elements from the beginning. addFirst() and removeFirst() are alternative names that do the same thing.

Example:

def list = new ArrayDeque([1, 2, 3, 4, 5])
def firstElement = list.pop()
assert firstElement == 1
list.push(0)
assert list as List == [0, 2, 3, 4, 5]
like image 6
ataylor Avatar answered Nov 16 '22 13:11

ataylor