blob: 0dbdf5861bac1561705aec3495b530cdbf769f0e [file] [log] [blame]
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--><head>
<meta charset='utf-8'/><meta http-equiv='X-UA-Compatible' content='IE=edge'/><meta name='viewport' content='width=device-width, initial-scale=1'/><meta name='keywords' content='groovy, lists, collections, guava, eclipse collections, commons collections, ginq, gquery, gpars, virtual threads, apache'/><meta name='description' content='This post looks at the common Groovy features for processing lists.'/><title>The Apache Groovy programming language - Blogs - Groovy List Processing Cheat Sheet</title><link href='../img/favicon.ico' type='image/x-ico' rel='icon'/><link rel='stylesheet' type='text/css' href='../css/bootstrap.css'/><link rel='stylesheet' type='text/css' href='../css/font-awesome.min.css'/><link rel='stylesheet' type='text/css' href='../css/style.css'/><link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css'/>
</head><body>
<div id='fork-me'>
<a href='https://github.com/apache/groovy'>
<img style='position: fixed; top: 20px; right: -58px; border: 0; z-index: 100; transform: rotate(45deg);' src='/img/horizontal-github-ribbon.png'/>
</a>
</div><div id='st-container' class='st-container st-effect-9'>
<nav class='st-menu st-effect-9' id='menu-12'>
<h2 class='icon icon-lab'>Socialize</h2><ul>
<li>
<a href='https://groovy-lang.org/mailing-lists.html' class='icon'><span class='fa fa-envelope'></span> Discuss on the mailing-list</a>
</li><li>
<a href='https://twitter.com/ApacheGroovy' class='icon'><span class='fa fa-twitter'></span> Groovy on Twitter</a>
</li><li>
<a href='https://groovy-lang.org/events.html' class='icon'><span class='fa fa-calendar'></span> Events and conferences</a>
</li><li>
<a href='https://github.com/apache/groovy' class='icon'><span class='fa fa-github'></span> Source code on GitHub</a>
</li><li>
<a href='https://groovy-lang.org/reporting-issues.html' class='icon'><span class='fa fa-bug'></span> Report issues in Jira</a>
</li><li>
<a href='http://stackoverflow.com/questions/tagged/groovy' class='icon'><span class='fa fa-stack-overflow'></span> Stack Overflow questions</a>
</li><li>
<a href='http://groovycommunity.com/' class='icon'><span class='fa fa-slack'></span> Slack Community</a>
</li>
</ul>
</nav><div class='st-pusher'>
<div class='st-content'>
<div class='st-content-inner'>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]--><div><div class='navbar navbar-default navbar-static-top' role='navigation'>
<div class='container'>
<div class='navbar-header'>
<button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span class='sr-only'></span><span class='icon-bar'></span><span class='icon-bar'></span><span class='icon-bar'></span>
</button><a class='navbar-brand' href='../index.html'>
<i class='fa fa-star'></i> Apache Groovy
</a>
</div><div class='navbar-collapse collapse'>
<ul class='nav navbar-nav navbar-right'>
<li class=''><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li class=''><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li class=''><a href='/download.html'>Download</a></li><li class=''><a href='https://groovy-lang.org/support.html'>Support</a></li><li class=''><a href='/'>Contribute</a></li><li class=''><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li class=''><a href='/blog'>Blog posts</a></li><li class=''><a href='https://groovy.apache.org/events.html'></a></li><li>
<a data-effect='st-effect-9' class='st-trigger' href='#'>Socialize</a>
</li><li class=''>
<a href='../search.html'>
<i class='fa fa-search'></i>
</a>
</li>
</ul>
</div>
</div>
</div><div id='content' class='page-1'><div class='row'><div class='row-fluid'><div class='col-lg-3'><ul class='nav-sidebar'><li><a href='./'>Blog index</a></li><li class='active'><a href='#doc'>Groovy List Processing Cheat Sheet</a></li><li><a href='#_declaring_lists' class='anchor-link'>Declaring lists</a></li><li><a href='#_list_elements_and_properties' class='anchor-link'>List elements and properties</a></li><li><a href='#_modifying_mutable_lists' class='anchor-link'>Modifying mutable lists</a></li><li><a href='#_additional_list_functionality' class='anchor-link'>Additional list functionality</a></li><li><a href='#_ginq_processing' class='anchor-link'>GINQ processing</a></li><li><a href='#_stream_methods' class='anchor-link'>Stream methods</a></li><li><a href='#_gpars' class='anchor-link'>GPars</a></li><li><a href='#_other_libraries' class='anchor-link'>Other libraries</a></li><li><a href='#_further_information' class='anchor-link'>Further Information</a></li><li><a href='#_conclusion' class='anchor-link'>Conclusion</a></li></ul><br/><ul class='nav-sidebar'><li style='padding: 0.35em 0.625em; background-color: #eee'><span>Related posts</span></li><li><a href='./groovy-null-processing'>Groovy Processing Nulls In Lists</a></li><li><a href='./zipping-collections-with-groovy'>Zipping Collections with Groovy</a></li><li><a href='./parsing-json-with-groovy'>Parsing JSON with Groovy</a></li><li><a href='./comparators-and-sorting-in-groovy'>Comparators and Sorting in Groovy</a></li><li><a href='./wordle-checker'>Checking Wordle with Groovy</a></li><li><a href='./fruity-eclipse-collections'>Fruity Eclipse Collections</a></li><li><a href='./deep-learning-and-eclipse-collections'>Deep Learning and Eclipse Collections</a></li><li><a href='./deck-of-cards-with-groovy'>Deck of cards with Groovy, JDK collections and Eclipse Collections</a></li><li><a href='./lego-bricks-with-groovy'>Lego Bricks with Groovy</a></li><li><a href='./gpars-meets-virtual-threads'>GPars meets Virtual Threads</a></li><li><a href='./groovy-haiku-processing'>Groovy Haiku processing</a></li></ul></div><div class='col-lg-8 col-lg-pull-0'><a name='doc'></a><h1>Groovy List Processing Cheat Sheet</h1><p><span>Author: <i>Paul King</i></span><br/><span>Published: 2022-08-28 08:46AM</span></p><hr/><div class="sect1">
<h2 id="_declaring_lists">Declaring lists</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Several styles are supported for declaring lists:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">var pets = ['cat', 'canary', 'dog', 'fish', 'gerbil'] // idiomatic Groovy
var nums = [1, 2, 3, 4] as LinkedList // use 'as' for other kinds of list
var primes = List.of(2, 3, 5, 7) // Java 9+ style (immutable)
var range = 1..4 // a range is also a list (immutable)
var bigNums = [1000, 2000].asUnmodifiable() // unmodifiable (backed by original)
var negNums = [-100, -200].asImmutable() // immutable (backed by copy)</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_list_elements_and_properties">List elements and properties</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Java methods for accessing list elements and list properties:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">assert !pets.isEmpty()
assert pets.size() == 5
assert pets.get(0) == 'cat'
assert pets.contains('dog')
assert pets.containsAll('cat', 'dog')
pets.forEach { assert it.size() &gt; 2 }
assert ['a', 'b', 'a'].indexOf('a') == 0
assert ['a', 'b', 'a'].lastIndexOf('a') == 2</code></pre>
</div>
</div>
<div class="paragraph">
<p>Groovy extensions for accessing list elements and list properties:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">assert pets[0] == 'cat'
assert pets?[0] == 'cat' // safe indexing returns null if pets was null instead of NPE
assert pets.first() == 'cat'
assert pets.head() == 'cat'
assert pets[-1] == 'gerbil'
assert pets[1..3] == ['canary', 'dog', 'fish']
assert pets[3..1] == ['fish', 'dog', 'canary'] // reverse range
assert pets[1, 3, 3] == ['canary', 'fish', 'fish'] // arbitrary collection
assert pets[0..1, [3, 3]] == ['cat', 'canary', 'fish', 'fish'] // nested collections
assert [1, 2, 3, 1].count(1) == 2
assert [1, 2, 3, 4].min() == 1
assert [1, 2, 3, 4].max() == 4
assert [1, 2, 3, 4].sum() == 10
assert [1, 2, 3, 4].average() == 2.5
[1, 2, 3, 4].eachWithIndex{ val, idx -&gt; assert val == idx + 1 }
def cpets = pets[0..1]
assert cpets == ['cat', 'canary']
assert pets.findAll { it =~ /c.*/ } == cpets
assert pets.find { it =~ /c.*/ } == cpets[0]
assert pets.grep(~/c.*/) == cpets
assert cpets.min { it.size() } == 'cat' // cpet with smallest size name
assert cpets.max { it.size() } == 'canary' // cpet with largest name
assert pets.groupBy { it.size() } == [3: ['cat', 'dog'], 4: ['fish'], 6: ['canary', 'gerbil']]
assert pets.countBy { it.size() } == [3: 2, 4: 1, 6: 2]
assert pets.sum{ it.size() } == 22 // total size of all pet names
assert pets.average{ it.size() } == 4.4 // average size of pet names
assert pets.indices == 0..4
assert pets.findIndexValues { it.size() == 6 } == [1, 4]
assert cpets.indexed() == [0: 'cat', 1: 'canary']
assert cpets.withIndex()*.toList() == [['cat', 0], ['canary', 1]]</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_modifying_mutable_lists">Modifying mutable lists</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Methods from Java for modifying lists:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">pets.remove(2); assert pets == ['cat', 'canary', 'fish', 'gerbil'] // remove by index
pets.remove('fish'); assert pets == ['cat', 'canary', 'gerbil'] // remove by element
pets.removeIf(p -&gt; p.startsWith("c")); assert pets == ['gerbil'] // remove by condition
pets.clear(); assert pets.isEmpty() // make empty
pets.add("kangaroo"); assert pets == ['kangaroo'] // add element
pets.add(0, "koala"); assert pets == ['koala', 'kangaroo'] // add element at index position
pets.addAll(['ant', 'bee']); assert pets == ['koala', 'kangaroo', 'ant', 'bee'] // add collection
pets.addAll(1, ['ant']); assert pets == ['koala', 'ant', 'kangaroo', 'ant', 'bee'] // add collection at index
pets.removeAll(['ant', 'flea']); assert pets == ['koala', 'kangaroo', 'bee'] // remove from collection
pets.retainAll(['bee', 'koala']); assert pets == ['koala', 'bee'] // retain from collection
pets.set(0, "zebra"); assert pets == ['zebra', 'bee'] // set element at index
pets.replaceAll(String::toUpperCase); assert pets == ['ZEBRA', 'BEE'] // replace elements by unary operator
pets.sort(Comparator.naturalOrder()); assert pets == ['BEE', 'ZEBRA'] // sort</code></pre>
</div>
</div>
<div class="paragraph">
<p>Groovy extensions for modifying lists:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">pets &lt;&lt; 'rock'; assert pets == ['BEE', 'ZEBRA', 'rock'] // leftShift append
pets += ['rabbit', 'rock', 'hare']; assert pets == ['BEE', 'ZEBRA', 'rock', 'rabbit', 'rock', 'hare'] // append collection
pets.unique(); assert pets == ['BEE', 'ZEBRA', 'rock', 'rabbit', 'hare'] // remove duplicates
pets.sort{ it.size() }; assert pets == ['BEE', 'rock', 'hare', 'ZEBRA', 'rabbit'] // sort by size
pets[0] = 'ant'; assert pets == ['ant', 'rock', 'hare', 'ZEBRA', 'rabbit'] // replace element by index
pets[1..3] = ['snake', 'SNAKE']; assert pets == ['ant', 'snake', 'SNAKE', 'rabbit'] // replace range of elements
pets.unique{it.toLowerCase() }; assert pets == ['ant', 'snake', 'rabbit'] // remove duplicates ignoring case
pets.reverse(true); assert pets == ['rabbit', 'snake', 'ant'] // flip
pets.shuffle(); assert pets.size() == 3; // shuffle elements; resulting order will vary
def dice = [1, 2, 3, 4, 5, 6]
dice.removeAt(2); assert dice == [1, 2, 4, 5, 6]
dice.removeElement(2); assert dice == [1, 4, 5, 6]
dice.removeLast(); assert dice == [1, 4, 5]
dice.swap(0, 2); assert dice == [5, 4, 1]</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_additional_list_functionality">Additional list functionality</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Methods and operators which return new lists or values:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">assert [1, 2, 3] + [1] == [1, 2, 3, 1]
assert [1, 2, 3, 1] - [1] == [2, 3]
assert [1, 2, 3] * 2 == [1, 2, 3, 1, 2, 3]
assert [1, [2, 3]].flatten() == [1, 2, 3]
assert [1, 2, 3].disjoint([4, 5, 6])
assert [1, 2, 3].intersect([4, 3, 1]) == [1, 3]
assert [1, 2, 3].collect { it + 3 } == [4, 5, 6]
assert [1, 2, 3, 4].collect { 1 } == [1, 1, 1, 1]
assert [4, 2, 1, 3].findAll { it % 2 == 0 } == [4, 2]
assert [1, 2, 3, 4].take(3) == [1, 2, 3]
assert [1, 2, 3, 4].takeRight(3) == [2, 3, 4]
assert [1, 2, 3, 4].takeWhile{ it &lt; 3 } == [1, 2]
assert [1, 2, 3, 4].drop(2) == [3, 4]
assert [1, 2, 3, 4].dropRight(2) == [1, 2]
assert [1, 2, 3, 4].dropWhile{it &lt; 3 } == [3, 4]
assert [1, 2, 3, 4].join('-') == '1-2-3-4'
assert [1, 2, 3, 4].tail() == [2, 3, 4]
assert [1, 2, 3, 4].init() == [1, 2, 3]
assert [1, 2, 3, 4].tails() == [[1, 2, 3, 4], [2, 3, 4], [3, 4], [4], []]
assert [1, 2, 3, 4].inits() == [[1, 2, 3, 4], [1, 2, 3], [1, 2], [1], []]
assert [1, 2, 3, 4].reverse() == [4, 3, 2, 1]
assert [1, 2, 3, 1].toUnique() == [1, 2, 3]
assert [1, 2, 3, 1].toSorted() == [1, 1, 2, 3]
assert [1, 2, 3, 4].collect { it * 2 } == [2, 4, 6, 8]
assert [[1, 2], [3, 4]].collectNested { it * 2 } == [[2, 4], [6, 8]]
def squaresAndCubesOfEvens = { it % 2 ? [] : [it**2, it**3] }
assert [1, 2, 3, 4].collectMany(squaresAndCubesOfEvens) == [4, 8, 16, 64]
assert [1, 2, 3, 4].any { it &gt; 3 }
assert [1, 2, 3, 4].every { it &lt; 5 }
assert ![1, 2, 3, 4].every { it &gt; 3 }
assert [1, 2, 3, 4].find { it &gt; 2 } == 3
assert [1, 2, 3, 4].findAll { it &gt; 2 } == [3, 4]
assert [1, 2, 3, 4].findIndexOf { it &gt; 2 } == 2
assert [1, 2, 3, 1].findLastIndexOf { it &gt; 2 } == 2
assert [1, 2, 3, 4].inject { acc, i -&gt; acc + i } == 10
assert (1..10).collate(3) == [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
assert (1..10).chop(1, 3, 2, -1) == [[1], [2, 3, 4], [5, 6], [7, 8, 9, 10]]
assert [1,2,3].permutations().toList() == [
[1, 2, 3], [3, 2, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1]
]
def matrix = [['a', 'b'], [ 1 , 2 ]]
assert matrix.transpose() == [ ['a', 1], ['b', 2] ]
assert matrix.combinations() == [ ['a', 1], ['b', 1], ['a', 2], ['b', 2] ]
assert [1, 2, 3].subsequences()*.toList() == [[1], [1, 2, 3], [2], [2, 3], [1, 2], [3], [1, 3]]
def answers = [1, 2, 3].withDefault{ 42 }
assert answers[2] == 3 &amp;&amp; answers[99] == 42</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_ginq_processing">GINQ processing</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Groovy also supports language integrated query support to process lists:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">// squares of odd numbers between 1 and 5
assert [1, 9, 25] == GQL {
from n in 1..5 where n % 2 != 0 select n ** 2
}
// group pets by name size
assert ["3:[cat, dog]", "4:[fish]", "6:[canary, gerbil]"] == GQL {
from p in pets
groupby p.size() as size
select size, agg(p) as names
}*.with{ "$it.size:$it.names" }</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_stream_methods">Stream methods</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Useful stream methods (it is worthwhile comparing these examples to earlier non-stream variants):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">pets = ['cat', 'canary', 'dog', 'fish', 'gerbil']
assert pets.stream().filter(p -&gt; p.size() == 3).map(String::toUpperCase).toList() == ['CAT', 'DOG']
assert pets.stream().map(p -&gt; p.size()).distinct().sorted().toList() == [3, 4, 6] // ordered pet name sizes
assert nums.stream().reduce{ a, b -&gt; a + b }.get() == 10
assert (1..10).stream().skip(3).limit(5).filter(i -&gt; i % 2 == 0).map(i -&gt; i ** 2).toList() == [16, 36, 64]
assert [1, 2, 3, 4].stream().flatMap(i -&gt; i % 2 ? Stream.empty() : Stream.of(i**2, i**3)).toList() == [4, 8, 16, 64]
assert pets.stream().collect(Collectors.groupingBy(p -&gt; p.size())) == [3:['cat', 'dog'], 4:['fish'], 6:['canary', 'gerbil']]
assert [1, 2, 3, 4].stream().map(Integer::toString).collect(Collectors.joining('-')) == '1-2-3-4'
Arrays.stream(0..9 as int[]).summaryStatistics().with {
assert sum == 45 &amp;&amp; min == 0 &amp;&amp; max == 9 &amp;&amp; average == 4.5 &amp;&amp; count == 10
}
assert pets.stream().allMatch(w -&gt; w ==~ /.*[aeiou].*/) // all pet names contain a vowel</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_gpars">GPars</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Before looking at <a href="http://gpars.org/">GPars</a>, it is worth looking at parallel stream processing:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">// calculate squares of odd numbers from input list
assert (1..5).parallelStream().filter{ it % 2 != 0 }.map(n -&gt; n ** 2).toList() == [1, 9, 25]</code></pre>
</div>
</div>
<div class="paragraph">
<p>GPars was designed to provide similar functionality long before streams processing was available. It still has some useful features.</p>
</div>
<div class="paragraph">
<p>Groovy has several tricks for removing the outer "withPool" clauses but we&#8217;ll do the longhand here. Two GPars variations of above streams example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">GParsPool.withPool {
assert (1..5).findAllParallel{ it % 2 }.collectParallel{ it ** 2 } == [1, 9, 25]
assert (1..5).parallel.filter{ it % 2 }.map{ it ** 2 }.collection == [1, 9, 25]
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or using (<a href="https://openjdk.java.net/jeps/425">JEP 425</a>) virtual threads:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">GParsExecutorsPool.withExistingPool(Executors.newVirtualThreadPerTaskExecutor()) {
assert (1..5).findAllParallel{ it % 2 }.collectParallel{ it ** 2 } == [1, 9, 25]
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_other_libraries">Other libraries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are numerous list-related libraries on the JVM. We&#8217;ll look at just a few.</p>
</div>
<div class="sect2">
<h3 id="_eclipse_collections">Eclipse collections</h3>
<div class="paragraph">
<p><a href="https://www.eclipse.org/collections/">Eclipse collections</a> comes with many container types including immutable collections, primitive collections, bimaps, multimaps and bags as well as numerous utility methods. It focuses on reduced memory footprint and efficient containers. It might be particularly of interest if you need primitive collections, immutable collections or some more exotic collection types like bag or bidirectional maps. Here are just a few examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">var certainties = Lists.immutable.of('death', 'taxes')
assert certainties.reduce{ a, b -&gt; "$a &amp; $b" }.get() == 'death &amp; taxes'
var numBag = Bags.immutable.with('One', 'One', 'Two', 'Three')
assert numBag.toMapOfItemToCount() == [One:2, Two:1, Three:1]
var biMap = BiMaps.immutable.with(6, "six", 2, "two")
assert biMap.inverse().six == 6</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_guava">Guava</h3>
<div class="paragraph">
<p><a href="https://github.com/google/guava/wiki">Guava</a> provides a number of extensions to the JDK collections ecosystem. In particular, it has immutable collections, new collection types like multisets and bidirectional maps and various powerful extensions and utilities. Here are a few examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">var set = TreeMultiset.create([1, 2, 3])
assert set == TreeMultiset.create([3, 2, 1])
set.addAll([1, 3, 5])
assert set.size() == 6 &amp;&amp; set.elementSet().size() == 4
assert set.toList() == [1, 1, 2, 3, 3, 5]
var bimap = HashBiMap.create()
bimap.five = 5
assert bimap.inverse()[5] == 'five'</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_apache_commons_collections">Apache Commons Collections</h3>
<div class="paragraph">
<p>The <a href="https://commons.apache.org/proper/commons-collections/">Apache Commons Collections</a> library extends upon the JDK collections framework adding some new types like bidirectional maps and bags as well as providing many comparator and iterator implementations. The library was designed to fill gaps in the JDK offerings and while some of those gaps in the JDK have now been filled by the JDK itself, Commons Collections still contains much useful functionality. Here are a few examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">var six = [six: 6] as TreeBidiMap
assert six.inverseBidiMap() == [6: 'six']
var bag = new HashBag(['one'] * 6)
bag.remove('one', 2)
assert bag.getCount('one') == 4</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_further_information">Further Information</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>GPars (<a href="http://gpars.org/">website</a>)</p>
</li>
<li>
<p>Eclipse Collections (<a href="https://www.eclipse.org/collections/">website</a> and <a href="https://github.com/eclipse/eclipse-collections">github site</a>)</p>
</li>
<li>
<p>Guava (<a href="https://github.com/google/guava/wiki">user guide</a>)</p>
</li>
<li>
<p>Apache Commons Collections (<a href="https://commons.apache.org/proper/commons-collections/">website</a>)</p>
</li>
<li>
<p><a href="https://www.manning.com/books/groovy-in-action-second-edition">Groovy in Action</a> (Appendix D has cheat sheets for Lists, GStrings, Closures, Regular expressions and GPath expressions)</p>
</li>
<li>
<p><a href="https://blog.mrhaki.com/2009/10/groovy-goodness-getting-tail-of-list.html">Groovy Goodness: Getting the Tail of a List</a></p>
</li>
<li>
<p><a href="https://blog.mrhaki.com/2011/09/groovy-goodness-take-and-drop-items.html">Groovy Goodness: Take and Drop Items from a List</a></p>
</li>
<li>
<p><a href="https://blog.mrhaki.com/2015/01/groovy-goodness-take-or-drop-last-items.html">Groovy Goodness: Take Or Drop Last Items From a Collection</a></p>
</li>
<li>
<p><a href="https://blog.mrhaki.com/2020/03/groovy-goodness-safe-index-based-access.html">Groovy Goodness: Safe Index Based Access For Lists, Arrays and Maps</a></p>
</li>
<li>
<p><a href="https://blog.mrhaki.com/2015/01/groovy-goodness-pop-and-push-items-in.html">Groovy Goodness: Pop And Push Items In a List</a></p>
</li>
<li>
<p><a href="https://www.baeldung.com/groovy-lists">Lists in Groovy</a> (Baeldung)</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We have looked at the more common methods for list processing with Groovy and a few other useful libraries.</p>
</div>
</div>
</div></div></div></div></div><footer id='footer'>
<div class='row'>
<div class='colset-3-footer'>
<div class='col-1'>
<h1>Groovy</h1><ul>
<li><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li><a href='/download.html'>Download</a></li><li><a href='https://groovy-lang.org/support.html'>Support</a></li><li><a href='/'>Contribute</a></li><li><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li><a href='/blog'>Blog posts</a></li><li><a href='https://groovy.apache.org/events.html'></a></li>
</ul>
</div><div class='col-2'>
<h1>About</h1><ul>
<li><a href='https://github.com/apache/groovy'>Source code</a></li><li><a href='https://groovy-lang.org/security.html'>Security</a></li><li><a href='https://groovy-lang.org/learn.html#books'>Books</a></li><li><a href='https://groovy-lang.org/thanks.html'>Thanks</a></li><li><a href='http://www.apache.org/foundation/sponsorship.html'>Sponsorship</a></li><li><a href='https://groovy-lang.org/faq.html'>FAQ</a></li><li><a href='https://groovy-lang.org/search.html'>Search</a></li>
</ul>
</div><div class='col-3'>
<h1>Socialize</h1><ul>
<li><a href='https://groovy-lang.org/mailing-lists.html'>Discuss on the mailing-list</a></li><li><a href='https://twitter.com/ApacheGroovy'>Groovy on Twitter</a></li><li><a href='https://groovy-lang.org/events.html'>Events and conferences</a></li><li><a href='https://github.com/apache/groovy'>Source code on GitHub</a></li><li><a href='https://groovy-lang.org/reporting-issues.html'>Report issues in Jira</a></li><li><a href='http://stackoverflow.com/questions/tagged/groovy'>Stack Overflow questions</a></li><li><a href='http://groovycommunity.com/'>Slack Community</a></li>
</ul>
</div><div class='col-right'>
<p>
The Groovy programming language is supported by the <a href='http://www.apache.org'>Apache Software Foundation</a> and the Groovy community.
</p><div text-align='right'>
<img src='../img/asf_logo.png' title='The Apache Software Foundation' alt='The Apache Software Foundation' style='width:60%'/>
</div><p>Apache&reg; and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation.</p>
</div>
</div><div class='clearfix'>&copy; 2003-2023 the Apache Groovy project &mdash; Groovy is Open Source: <a href='http://www.apache.org/licenses/LICENSE-2.0.html' alt='Apache 2 License'>license</a>, <a href='https://privacy.apache.org/policies/privacy-policy-public.html'>privacy policy</a>.</div>
</div>
</footer></div>
</div>
</div>
</div>
</div><script src='../js/vendor/jquery-1.10.2.min.js' defer></script><script src='../js/vendor/classie.js' defer></script><script src='../js/vendor/bootstrap.js' defer></script><script src='../js/vendor/sidebarEffects.js' defer></script><script src='../js/vendor/modernizr-2.6.2.min.js' defer></script><script src='../js/plugins.js' defer></script><script src='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js'></script><script>document.addEventListener('DOMContentLoaded',prettyPrint)</script><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-257558-10', 'auto');
ga('send', 'pageview');
</script>
</body></html>