You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/08/02 18:59:52 UTC

[groovy] 03/03: sort `f` and `g` methods

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 70c17c26afbed767dc4af08b49ad0f2e185ef792
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Aug 2 13:33:22 2023 -0500

    sort `f` and `g` methods
---
 .../groovy/runtime/DefaultGroovyMethods.java       | 14998 ++++++++++---------
 1 file changed, 7528 insertions(+), 7470 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 3ef8d4f78d..dfd3220778 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -28,7 +28,6 @@ import groovy.lang.GString;
 import groovy.lang.GroovyObject;
 import groovy.lang.GroovyRuntimeException;
 import groovy.lang.GroovySystem;
-import groovy.lang.Groovydoc;
 import groovy.lang.IntRange;
 import groovy.lang.ListWithDefault;
 import groovy.lang.MapWithDefault;
@@ -4522,1905 +4521,1727 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     //--------------------------------------------------------------------------
+    // find
 
     /**
-     * Identity check. Since == is overridden in Groovy with the meaning of equality
-     * we need some fallback to check for object identity.  Invoke using the
-     * 'is' method, like so: <code>def same = this.is(that)</code>
+     * Finds the first value matching the closure condition.
      *
-     * @param self  an object
-     * @param other an object to compare identity with
-     * @return true if self and other are both references to the same
-     *         instance, false otherwise
-     * @since 1.0
-     */
-    public static boolean is(Object self, Object other) {
-        return self == other;
-    }
-
-    /**
-     * Allows the closure to be called for the object reference self.
-     * Synonym for 'with()'.
+     * <pre class="groovyTestCase">
+     * def numbers = [1, 2, 3]
+     * def result = numbers.find { it {@code >} 1}
+     * assert result == 2
+     * </pre>
      *
-     * @param self    the object to have a closure act upon
-     * @param closure the closure to call on the object
-     * @return result of calling the closure
-     * @see #with(Object, Closure)
+     * @param self    an Object with an iterator returning its values
+     * @param closure a closure condition
+     * @return the first Object found or null if none was found
      * @since 1.0
      */
-    public static <T,U> T identity(
-            @DelegatesTo.Target("self") U self,
-            @DelegatesTo(value=DelegatesTo.Target.class,
-                    target="self",
-                    strategy=Closure.DELEGATE_FIRST)
-            @ClosureParams(FirstParam.class)
-                    Closure<T> closure) {
-        return DefaultGroovyMethods.with(self, closure);
+    public static Object find(Object self, Closure closure) {
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            Object value = iter.next();
+            if (bcw.call(value)) {
+                return value;
+            }
+        }
+        return null;
     }
 
     /**
-     * Allows the closure to be called for the object reference self.
+     * Finds the first item matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
      * <p>
-     * Any method invoked inside the closure will first be invoked on the
-     * self reference. For instance, the following method calls to the append()
-     * method are invoked on the StringBuilder instance:
+     * Example:
      * <pre class="groovyTestCase">
-     * def b = new StringBuilder().with {
-     *   append('foo')
-     *   append('bar')
-     *   return it
-     * }
-     * assert b.toString() == 'foobar'
-     * </pre>
-     * This is commonly used to simplify object creation, such as this example:
-     * <pre>
-     * def p = new Person().with {
-     *   firstName = 'John'
-     *   lastName = 'Doe'
-     *   return it
-     * }
-     * </pre>
-     * The other typical usage, uses the self object while creating some value:
-     * <pre>
-     * def fullName = person.with{ "$firstName $lastName" }
+     * def items = [null, 0, 0.0, false, '', [], 42, 43]
+     * assert items.find() == 42
      * </pre>
      *
-     * @param self    the object to have a closure act upon
-     * @param closure the closure to call on the object
-     * @return result of calling the closure
-     * @see #with(Object, boolean, Closure)
-     * @see #tap(Object, Closure)
-     * @since 1.5.0
+     * @param self    an Object with an Iterator returning its values
+     * @return the first Object found or null if none was found
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    @SuppressWarnings("unchecked")
-    public static <T,U> T with(
-            @DelegatesTo.Target("self") U self,
-            @DelegatesTo(value=DelegatesTo.Target.class,
-                    target="self",
-                    strategy=Closure.DELEGATE_FIRST)
-            @ClosureParams(FirstParam.class)
-            Closure<T> closure) {
-        return (T) with(self, false, (Closure<Object>)closure);
+    public static Object find(Object self) {
+        return find(self, Closure.IDENTITY);
     }
 
     /**
-     * Allows the closure to be called for the object reference self.
-     * <p/>
-     * Any method invoked inside the closure will first be invoked on the
-     * self reference. For example, the following method calls to the append()
-     * method are invoked on the StringBuilder instance and then, because
-     * 'returning' is true, the self instance is returned:
-     * <pre class="groovyTestCase">
-     * def b = new StringBuilder().with(true) {
-     *   append('foo')
-     *   append('bar')
-     * }
-     * assert b.toString() == 'foobar'
-     * </pre>
-     * The returning parameter is commonly set to true when using with to simplify object
-     * creation, such as this example:
-     * <pre>
-     * def p = new Person().with(true) {
-     *   firstName = 'John'
-     *   lastName = 'Doe'
-     * }
-     * </pre>
-     * Alternatively, 'tap' is an alias for 'with(true)', so that method can be used instead.
-     *
-     * The other main use case for with is when returning a value calculated using self as shown here:
-     * <pre>
-     * def fullName = person.with(false){ "$firstName $lastName" }
+     * Finds the first value matching the closure condition.  Example:
+     * <pre class="groovyTestCase">def list = [1,2,3]
+     * assert 2 == list.find { it {@code >} 1 }
      * </pre>
-     * Alternatively, 'with' is an alias for 'with(false)', so the boolean parameter can be omitted instead.
      *
-     * @param self      the object to have a closure act upon
-     * @param returning if true, return the self object; otherwise, the result of calling the closure
-     * @param closure   the closure to call on the object
-     * @return the self object or the result of calling the closure depending on 'returning'
-     * @see #with(Object, Closure)
-     * @see #tap(Object, Closure)
-     * @since 2.5.0
+     * @param self    a Collection
+     * @param closure a closure condition
+     * @return the first Object found, in the order of the collections iterator, or null if no element matches
+     * @since 1.0
      */
-    public static <T,U extends T, V extends T> T with(
-            @DelegatesTo.Target("self") U self,
-            boolean returning,
-            @DelegatesTo(value=DelegatesTo.Target.class,
-                    target="self",
-                    strategy=Closure.DELEGATE_FIRST)
-            @ClosureParams(FirstParam.class)
-            Closure<T> closure) {
-        @SuppressWarnings("unchecked")
-        final Closure<V> clonedClosure = (Closure<V>) closure.clone();
-        clonedClosure.setResolveStrategy(Closure.DELEGATE_FIRST);
-        clonedClosure.setDelegate(self);
-        V result = clonedClosure.call(self);
-        return returning ? self : result;
+    public static <T> T find(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+        for (T value : self) {
+            if (bcw.call(value)) {
+                return value;
+            }
+        }
+        return null;
     }
 
     /**
-     * Allows the closure to be called for the object reference self (similar
-     * to <code>with</code>) and always returns self.
+     * Finds the first item matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
      * <p>
-     * Any method invoked inside the closure will first be invoked on the
-     * self reference. For instance, the following method calls to the append()
-     * method are invoked on the StringBuilder instance:
-     * <pre>
-     * def b = new StringBuilder().tap {
-     *   append('foo')
-     *   append('bar')
-     * }
-     * assert b.toString() == 'foobar'
-     * </pre>
-     * This is commonly used to simplify object creation, such as this example:
-     * <pre>
-     * def p = new Person().tap {
-     *   firstName = 'John'
-     *   lastName = 'Doe'
-     * }
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [null, 0, 0.0, false, '', [], 42, 43]
+     * assert items.find() == 42
      * </pre>
      *
-     * @param self    the object to have a closure act upon
-     * @param closure the closure to call on the object
-     * @return self
-     * @see #with(Object, boolean, Closure)
-     * @see #with(Object, Closure)
-     * @since 2.5.0
+     * @param self    a Collection
+     * @return the first Object found or null if none was found
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    @SuppressWarnings("unchecked")
-    public static <T,U> U tap(
-            @DelegatesTo.Target("self") U self,
-            @DelegatesTo(value=DelegatesTo.Target.class,
-                    target="self",
-                    strategy=Closure.DELEGATE_FIRST)
-            @ClosureParams(FirstParam.class)
-            Closure<T> closure) {
-        return (U) with(self, true, (Closure<Object>)closure);
+    public static <T> T find(Collection<T> self) {
+        return find(self, Closure.IDENTITY);
     }
 
     /**
-     * Allows the subscript operator to be used to lookup dynamic property values.
-     * <code>bean[somePropertyNameExpression]</code>. The normal property notation
-     * of groovy is neater and more concise but only works with compile-time known
-     * property names.
+     * Finds the first entry matching the closure condition.
+     * If the closure takes two parameters, the entry key and value are passed.
+     * If the closure takes one parameter, the Map.Entry object is passed.
+     * <pre class="groovyTestCase">assert [a:1, b:3].find { it.value == 3 }.key == "b"</pre>
      *
-     * @param self     the object to act upon
-     * @param property the property name of interest
-     * @return the property value
+     * @param self    a Map
+     * @param closure a 1 or 2 arg Closure condition
+     * @return the first Object found
      * @since 1.0
      */
-    public static Object getAt(Object self, String property) {
-        return InvokerHelper.getProperty(self, property);
+    public static <K, V> Map.Entry<K, V> find(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<?> closure) {
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            if (bcw.callForMap(entry)) {
+                return entry;
+            }
+        }
+        return null;
     }
 
+    //--------------------------------------------------------------------------
+    // findAll
+
     /**
-     * Allows the subscript operator to be used to set dynamically named property values.
-     * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
-     * of groovy is neater and more concise but only works with property names which
-     * are known at compile time.
+     * Finds all entries matching the closure condition. If the
+     * closure takes one parameter then it will be passed the Map.Entry.
+     * Otherwise if the closure should take two parameters, which will be
+     * the key and the value.
+     * <p>
+     * If the <code>self</code> map is one of TreeMap, LinkedHashMap, Hashtable
+     * or Properties, the returned Map will preserve that type, otherwise a HashMap will
+     * be returned.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * def result = [a:1, b:2, c:4, d:5].findAll { it.value % 2 == 0 }
+     * assert result.every { it instanceof Map.Entry }
+     * assert result*.key == ["b", "c"]
+     * assert result*.value == [2, 4]
+     * </pre>
      *
-     * @param self     the object to act upon
-     * @param property the name of the property to set
-     * @param newValue the value to set
+     * @param self    a Map
+     * @param closure a 1 or 2 arg Closure condition applying on the entries
+     * @return a new subMap
      * @since 1.0
      */
-    public static void putAt(Object self, String property, Object newValue) {
-        InvokerHelper.setProperty(self, property, newValue);
-    }
-
+    public static <K, V> Map<K, V> findAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure closure) {
+        Map<K, V> answer = createSimilarMap(self);
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            if (bcw.callForMap(entry)) {
+                answer.put(entry.getKey(), entry.getValue());
+            }
+        }
+        return answer;
+    }
+
     /**
-     * Retrieves the list of {@link groovy.lang.MetaProperty} objects for 'self' and wraps it
-     * in a list of {@link groovy.lang.PropertyValue} objects that additionally provide
-     * the value for each property of 'self'.
+     * Finds all values matching the closure condition.
+     * <pre class="groovyTestCase">assert ([2,4] as Set) == ([1,2,3,4] as Set).findAll { it % 2 == 0 }</pre>
      *
-     * @param self the receiver object
-     * @return list of {@link groovy.lang.PropertyValue} objects
-     * @see groovy.util.Expando#getMetaPropertyValues()
-     * @since 1.0
+     * @param self    a Set
+     * @param closure a closure condition
+     * @return a Set of matching values
+     * @since 2.4.0
      */
-    public static List<PropertyValue> getMetaPropertyValues(Object self) {
-        MetaClass metaClass = InvokerHelper.getMetaClass(self);
-        List<MetaProperty> mps = metaClass.getProperties();
-        List<PropertyValue> props = new ArrayList<>(mps.size());
-        for (MetaProperty mp : mps) {
-            props.add(new PropertyValue(self, mp));
-        }
-        return props;
+    public static <T> Set<T> findAll(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (Set<T>) findAll((Collection<T>) self, closure);
     }
 
     /**
-     * Convenience method that calls {@link #getMetaPropertyValues(java.lang.Object)}(self)
-     * and provides the data in form of simple key/value pairs, i.e. without
-     * type() information.
+     * Finds all values matching the closure condition.
+     * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
      *
-     * @param self the receiver object
-     * @return meta properties as Map of key/value pairs
-     * @since 1.0
+     * @param self    a List
+     * @param closure a closure condition
+     * @return a List of matching values
+     * @since 2.4.0
      */
-    public static Map<String, Object> getProperties(Object self) {
-        List<PropertyValue> metaProps = getMetaPropertyValues(self);
-        Map<String, Object> props = new LinkedHashMap<>(metaProps.size());
-
-        for (PropertyValue mp : metaProps) {
-            try {
-                props.put(mp.getName(), mp.getValue());
-            } catch (Exception e) {
-                java.util.logging.Logger.getLogger(DefaultGroovyMethods.class.getName())
-                    .throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
-            }
-        }
-        return props;
+    public static <T> List<T> findAll(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<T>) findAll((Collection<T>) self, closure);
     }
 
     /**
-     * Scoped use method
+     * Finds all values matching the closure condition.
+     * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
      *
-     * @param self          any Object
-     * @param categoryClass a category class to use
-     * @param closure       the closure to invoke with the category in place
-     * @return the value returned from the closure
-     * @since 1.0
+     * @param self    a Collection
+     * @param closure a closure condition
+     * @return a Collection of matching values
+     * @since 1.5.6
      */
-    public static <T> T use(Object self, Class categoryClass, Closure<T> closure) {
-        return GroovyCategorySupport.use(categoryClass, closure);
+    public static <T> Collection<T> findAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return findMany(createSimilarCollection(self), self.iterator(), closure);
     }
 
     /**
-     * Extend object with category methods.
-     * All methods for given class and all super classes will be added to the object.
+     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null] as Set
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]] as Set
+     * </pre>
      *
-     * @param self          any Class
-     * @param categoryClasses a category classes to use
-     * @since 1.6.0
+     * @param self a Set
+     * @return a Set of the truthy values
+     * @since 2.4.0
+     * @see Closure#IDENTITY
      */
-    public static void mixin(MetaClass self, List<Class> categoryClasses) {
-        MixinInMetaClass.mixinClassesToMetaClass(self, categoryClasses);
+    public static <T> Set<T> findAll(Set<T> self) {
+        return findAll(self, Closure.IDENTITY);
     }
 
     /**
-     * Extend class globally with category methods.
-     * All methods for given class and all super classes will be added to the class.
+     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
      *
-     * @param self          any Class
-     * @param categoryClasses a category classes to use
-     * @since 1.6.0
+     * @param self a List
+     * @return a List of the truthy values
+     * @since 2.4.0
+     * @see Closure#IDENTITY
      */
-    public static void mixin(Class self, List<Class> categoryClasses) {
-        mixin(getMetaClass(self), categoryClasses);
+    public static <T> List<T> findAll(List<T> self) {
+        return findAll(self, Closure.IDENTITY);
     }
 
     /**
-     * Extend class globally with category methods.
+     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
      *
-     * @param self          any Class
-     * @param categoryClass a category class to use
-     * @since 1.6.0
+     * @param self a Collection
+     * @return a Collection of the truthy values
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    public static void mixin(Class self, Class categoryClass) {
-        mixin(getMetaClass(self), Collections.singletonList(categoryClass));
+    public static <T> Collection<T> findAll(Collection<T> self) {
+        return findAll(self, Closure.IDENTITY);
     }
 
     /**
-     * Extend class globally with category methods.
+     * Finds all items matching the closure condition.
      *
-     * @param self          any Class
-     * @param categoryClass a category class to use
+     * @param self    an Object with an Iterator returning its values
+     * @param closure a closure condition
+     * @return a List of the values found
      * @since 1.6.0
      */
-    public static void mixin(Class self, Class[] categoryClass) {
-        mixin(getMetaClass(self), Arrays.asList(categoryClass));
+    @SuppressWarnings("unchecked")
+    public static List findAll(Object self, Closure closure) {
+        return findMany(new ArrayList(), InvokerHelper.asIterator(self), closure);
     }
 
     /**
-     * Extend class globally with category methods.
+     * Finds all items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
      *
-     * @param self          any Class
-     * @param categoryClass a category class to use
-     * @since 1.6.0
+     * @param self an Object with an Iterator returning its values
+     * @return a List of the truthy values
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    public static void mixin(MetaClass self, Class categoryClass) {
-        mixin(self, Collections.singletonList(categoryClass));
+    public static List findAll(Object self) {
+        return findAll(self, Closure.IDENTITY);
+    }
+
+    static <T, C extends Collection<T>> C findMany(C collector, Iterator<? extends T> iter, Closure<?> closure) {
+        BooleanClosureWrapper test = new BooleanClosureWrapper(closure);
+        while (iter.hasNext()) {
+            T value = iter.next();
+            if (test.call(value)) {
+                collector.add(value);
+            }
+        }
+        return collector;
     }
 
+    //--------------------------------------------------------------------------
+    // findIndexOf
+
     /**
-     * Extend class globally with category methods.
+     * Iterates over the elements of an aggregate of items and returns
+     * the index of the first item that matches the condition specified in the closure.
      *
-     * @param self          any Class
-     * @param categoryClass a category class to use
-     * @since 1.6.0
+     * @param self      the iteration object over which to iterate
+     * @param condition the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 1.0
      */
-    public static void mixin(MetaClass self, Class[] categoryClass) {
-        mixin(self, Arrays.asList(categoryClass));
+    public static int findIndexOf(Object self, Closure condition) {
+        return findIndexOf(self, 0, condition);
     }
 
     /**
-     * Gets the url of the jar file/source file containing the specified class
+     * Iterates over the elements of an aggregate of items, starting from a
+     * specified startIndex, and returns the index of the first item that matches the
+     * condition specified in the closure.
+     * Example (aggregate is {@code ChronoUnit} enum values):
+     * <pre class="groovyTestCase">
+     * import java.time.temporal.ChronoUnit
+     * def nameStartsWithM = { it.name().startsWith('M') }
+     * def first  = ChronoUnit.findIndexOf(nameStartsWithM)
+     * def second = ChronoUnit.findIndexOf(first + 1, nameStartsWithM)
+     * def third  = ChronoUnit.findIndexOf(second + 1, nameStartsWithM)
+     * Set units  = [first, second, third]
+     * assert !units.contains(-1) // should have found 3 of MICROS, MILLIS, MINUTES, MONTHS, ...
+     * assert units.size() == 3 // just check size so as not to rely on order
+     * </pre>
      *
-     * @param self the class
-     * @return the url of the jar, {@code null} if the specified class is from JDK
-     * @since 2.5.0
+     * @param self       the iteration object over which to iterate
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 1.5.0
      */
-    public static URL getLocation(Class self) {
-        CodeSource codeSource = self.getProtectionDomain().getCodeSource();
-
-        return null == codeSource ? null : codeSource.getLocation();
+    public static int findIndexOf(Object self, int startIndex, Closure condition) {
+        return findIndexOf(InvokerHelper.asIterator(self), startIndex, condition);
     }
 
     /**
-     * Scoped use method with list of categories.
+     * Iterates over the elements of an Iterator and returns the index of the first item that satisfies the
+     * condition specified by the closure.
      *
-     * @param self              any Object
-     * @param categoryClassList a list of category classes
-     * @param closure           the closure to invoke with the categories in place
-     * @return the value returned from the closure
-     * @since 1.0
+     * @param self      an Iterator
+     * @param condition the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static <T> T use(Object self, List<Class> categoryClassList, Closure<T> closure) {
-        return GroovyCategorySupport.use(categoryClassList, closure);
+    public static <T> int findIndexOf(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexOf(self, 0, condition);
     }
 
     /**
-     * Allows you to use a list of categories, specifying the list as varargs.
-     * <code>use(CategoryClass1, CategoryClass2) { ... }</code>
-     * This method saves having to wrap the category
-     * classes in a list.
+     * Iterates over the elements of an Iterator, starting from a
+     * specified startIndex, and returns the index of the first item that satisfies the
+     * condition specified by the closure.
      *
-     * @param self  any Object
-     * @param array a list of category classes and a Closure
-     * @return the value returned from the closure
-     * @since 1.0
+     * @param self       an Iterator
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    @SuppressWarnings("unchecked")
-    public static Object use(Object self, Object[] array) {
-        if (array.length < 2)
-            throw new IllegalArgumentException(
-                    "Expecting at least 2 arguments, a category class and a Closure");
-        Closure closure;
-        try {
-            closure = (Closure) array[array.length - 1];
-        } catch (ClassCastException e) {
-            throw new IllegalArgumentException("Expecting a Closure to be the last argument");
-        }
-        List<Class> list = new ArrayList<>(array.length - 1);
-        for (int i = 0; i < array.length - 1; ++i) {
-            Class categoryClass;
-            try {
-                categoryClass = (Class) array[i];
-            } catch (ClassCastException e) {
-                throw new IllegalArgumentException("Expecting a Category Class for argument " + i);
+    public static <T> int findIndexOf(Iterator<T> self, int startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        int result = -1;
+        int i = 0;
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
+        while (self.hasNext()) {
+            Object value = self.next();
+            if (i++ < startIndex) {
+                continue;
+            }
+            if (bcw.call(value)) {
+                result = i - 1;
+                break;
             }
-            list.add(categoryClass);
-        }
-        return GroovyCategorySupport.use(list, closure);
-    }
-
-    private static Object getClosureOwner(Closure<?> cls) {
-        Object owner =  cls.getOwner();
-        while (owner instanceof GeneratedClosure) {
-            owner = ((Closure<?>) owner).getOwner();
         }
-        return owner;
+        return result;
     }
 
     /**
-     * Inspects returns the String that matches what would be typed into a
-     * terminal to create this object.
+     * Iterates over the elements of an Iterable and returns the index of the first item that satisfies the
+     * condition specified by the closure.
      *
-     * @param self any Object
-     * @return a String that matches what would be typed into a terminal to
-     *         create this object. e.g. [1, 'hello'].inspect() {@code ->} [1, 'hello']
-     * @since 1.0
+     * @param self      an Iterable
+     * @param condition the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static String inspect(Object self) {
-        return FormatHelper.inspect(self);
+    public static <T> int findIndexOf(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexOf(self, 0, condition);
     }
 
     /**
-     * Provide a dynamic method invocation method which can be overloaded in
-     * classes to implement dynamic proxies easily.
+     * Iterates over the elements of an Iterable, starting from a
+     * specified startIndex, and returns the index of the first item that satisfies the
+     * condition specified by the closure.
      *
-     * @param object    any Object
-     * @param method    the name of the method to call
-     * @param arguments the arguments to use
-     * @return the result of the method call
-     * @since 1.0
+     * @param self       an Iterable
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the first matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static Object invokeMethod(Object object, String method, Object arguments) {
-        return InvokerHelper.invokeMethod(object, method, arguments);
+    public static <T> int findIndexOf(Iterable<T> self, int startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexOf(self.iterator(), startIndex, condition);
     }
 
     //--------------------------------------------------------------------------
-    // print/println/printf/sprintf
+    // findIndexValues
 
     /**
-     * Print a value formatted Groovy style to self if it
-     * is a Writer, otherwise to the standard output stream.
+     * Iterates over the elements of an aggregate of items and returns
+     * the index values of the items that match the condition specified in the closure.
      *
-     * @param self  any Object
-     * @param value the value to print
-     * @since 1.0
+     * @param self      the iteration object over which to iterate
+     * @param condition the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 1.5.2
      */
-    public static void print(Object self, Object value) {
-        // we won't get here if we are a PrintWriter
-        if (self instanceof Writer) {
-            try {
-                ((Writer) self).write(FormatHelper.toString(value));
-            } catch (IOException e) {
-                // TODO: Should we have some unified function like PrintWriter.checkError()?
-            }
-        } else {
-            System.out.print(FormatHelper.toString(value));
-        }
+    public static List<Number> findIndexValues(Object self, Closure condition) {
+        return findIndexValues(self, 0, condition);
     }
 
     /**
-     * Print a value formatted Groovy style to the print writer.
+     * Iterates over the elements of an aggregate of items, starting from
+     * a specified startIndex, and returns the index values of the items that match
+     * the condition specified in the closure.
      *
-     * @param self  a PrintWriter
-     * @param value the value to print
-     * @since 1.0
+     * @param self       the iteration object over which to iterate
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 1.5.2
      */
-    public static void print(PrintWriter self, Object value) {
-        self.print(FormatHelper.toString(value));
+    public static List<Number> findIndexValues(Object self, Number startIndex, Closure condition) {
+        return findIndexValues(InvokerHelper.asIterator(self), startIndex, condition);
     }
 
     /**
-     * Print a value formatted Groovy style to the print stream.
+     * Iterates over the elements of an Iterator and returns
+     * the index values of the items that match the condition specified in the closure.
      *
-     * @param self  a PrintStream
-     * @param value the value to print
-     * @since 1.6.0
+     * @param self      an Iterator
+     * @param condition the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 2.5.0
      */
-    public static void print(PrintStream self, Object value) {
-        self.print(FormatHelper.toString(value));
+    public static <T> List<Number> findIndexValues(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexValues(self, 0, condition);
     }
 
     /**
-     * Print a value to the standard output stream.
-     * This method delegates to the owner to execute the method.
+     * Iterates over the elements of an Iterator, starting from
+     * a specified startIndex, and returns the index values of the items that match
+     * the condition specified in the closure.
      *
-     * @param self  a generated closure
-     * @param value the value to print
-     * @since 1.0
+     * @param self       an Iterator
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 2.5.0
      */
-    public static void print(Closure self, Object value) {
-        Object owner = getClosureOwner(self);
-        InvokerHelper.invokeMethod(owner, "print", new Object[]{value});
+    public static <T> List<Number> findIndexValues(Iterator<T> self, Number startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        List<Number> result = new ArrayList<>();
+        long count = 0;
+        long startCount = startIndex.longValue();
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
+        while (self.hasNext()) {
+            Object value = self.next();
+            if (count++ < startCount) {
+                continue;
+            }
+            if (bcw.call(value)) {
+                result.add(count - 1);
+            }
+        }
+        return result;
     }
 
     /**
-     * Print to a console in interactive format.
+     * Iterates over the elements of an Iterable and returns
+     * the index values of the items that match the condition specified in the closure.
      *
-     * @param self any Object
-     * @param out  the PrintWriter used for printing
-     * @since 1.0
+     * @param self      an Iterable
+     * @param condition the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 2.5.0
      */
-    public static void print(Object self, PrintWriter out) {
-        if (out == null) {
-            out = new PrintWriter(System.out);
-        }
-        out.print(FormatHelper.toString(self));
+    public static <T> List<Number> findIndexValues(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexValues(self, 0, condition);
     }
 
     /**
-     * Print a linebreak to the standard output stream.
+     * Iterates over the elements of an Iterable, starting from
+     * a specified startIndex, and returns the index values of the items that match
+     * the condition specified in the closure.
      *
-     * @param self any Object
-     * @since 1.0
+     * @param self       an Iterable
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return a list of numbers corresponding to the index values of all matched objects
+     * @since 2.5.0
      */
-    public static void println(Object self) {
-        // we won't get here if we are a PrintWriter
-        if (self instanceof Writer) {
-            PrintWriter pw = new GroovyPrintWriter((Writer) self);
-            pw.println();
-        } else {
-            System.out.println();
-        }
+    public static <T> List<Number> findIndexValues(Iterable<T> self, Number startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findIndexValues(self.iterator(), startIndex, condition);
     }
 
+    //--------------------------------------------------------------------------
+    // findLastIndexOf
+
     /**
-     * Print a linebreak to the standard output stream.
-     * This method delegates to the owner to execute the method.
+     * Iterates over the elements of an aggregate of items and returns
+     * the index of the last item that matches the condition specified in the closure.
+     * Example (aggregate is {@code ChronoUnit} enum values):
+     * <pre class="groovyTestCase">
+     * import java.time.temporal.ChronoUnit
+     * def nameStartsWithM = { it.name().startsWith('M') }
+     * def first = ChronoUnit.findIndexOf(nameStartsWithM)
+     * def last  = ChronoUnit.findLastIndexOf(nameStartsWithM)
+     * // should have found 2 unique index values for MICROS, MILLIS, MINUTES, MONTHS, ...
+     * assert first != -1 &amp;&amp; last != -1 &amp;&amp; first != last
+     * </pre>
      *
-     * @param self  a closure
-     * @since 1.0
+     * @param self      the iteration object over which to iterate
+     * @param condition the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 1.5.2
      */
-    public static void println(Closure self) {
-        Object owner = getClosureOwner(self);
-        InvokerHelper.invokeMethod(owner, "println", InvokerHelper.EMPTY_ARGS);
+    public static int findLastIndexOf(Object self, Closure condition) {
+        return findLastIndexOf(self, 0, condition);
     }
 
     /**
-     * Print a value formatted Groovy style (followed by a newline) to self
-     * if it is a Writer, otherwise to the standard output stream.
+     * Iterates over the elements of an aggregate of items, starting
+     * from a specified startIndex, and returns the index of the last item that
+     * matches the condition specified in the closure.
      *
-     * @param self  any Object
-     * @param value the value to print
-     * @since 1.0
+     * @param self       the iteration object over which to iterate
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 1.5.2
      */
-    public static void println(Object self, Object value) {
-        // we won't get here if we are a PrintWriter
-        if (self instanceof Writer) {
-            final PrintWriter pw = new GroovyPrintWriter((Writer) self);
-            pw.println(value);
-        } else {
-            System.out.println(FormatHelper.toString(value));
-        }
+    public static int findLastIndexOf(Object self, int startIndex, Closure condition) {
+        return findLastIndexOf(InvokerHelper.asIterator(self), startIndex, condition);
     }
 
     /**
-     * Print a value formatted Groovy style (followed by a newline) to the print writer.
+     * Iterates over the elements of an Iterator and returns
+     * the index of the last item that matches the condition specified in the closure.
      *
-     * @param self  a PrintWriter
-     * @param value the value to print
-     * @since 1.0
+     * @param self      an Iterator
+     * @param condition the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static void println(PrintWriter self, Object value) {
-        self.println(FormatHelper.toString(value));
+    public static <T> int findLastIndexOf(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findLastIndexOf(self, 0, condition);
     }
 
     /**
-     * Print a value formatted Groovy style (followed by a newline) to the print stream.
+     * Iterates over the elements of an Iterator, starting
+     * from a specified startIndex, and returns the index of the last item that
+     * matches the condition specified in the closure.
      *
-     * @param self  any Object
-     * @param value the value to print
-     * @since 1.6.0
+     * @param self       an Iterator
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static void println(PrintStream self, Object value) {
-        self.println(FormatHelper.toString(value));
+    public static <T> int findLastIndexOf(Iterator<T> self, int startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        int result = -1;
+        int i = 0;
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
+        while (self.hasNext()) {
+            Object value = self.next();
+            if (i++ < startIndex) {
+                continue;
+            }
+            if (bcw.call(value)) {
+                result = i - 1;
+            }
+        }
+        return result;
     }
 
     /**
-     * Print a value (followed by a newline) to the standard output stream.
-     * This method delegates to the owner to execute the method.
+     * Iterates over the elements of an Iterable and returns
+     * the index of the last item that matches the condition specified in the closure.
      *
-     * @param self  a closure
-     * @param value the value to print
-     * @since 1.0
+     * @param self      an Iterable
+     * @param condition the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static void println(Closure self, Object value) {
-        Object owner = getClosureOwner(self);
-        InvokerHelper.invokeMethod(owner, "println", new Object[]{value});
+    public static <T> int findLastIndexOf(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findLastIndexOf(self.iterator(), 0, condition);
     }
 
     /**
-     * Print to a console in interactive format.
+     * Iterates over the elements of an Iterable, starting
+     * from a specified startIndex, and returns the index of the last item that
+     * matches the condition specified in the closure.
      *
-     * @param self any Object
-     * @param out  the PrintWriter used for printing
-     * @since 1.0
+     * @param self       an Iterable
+     * @param startIndex start matching from this index
+     * @param condition  the matching condition
+     * @return an integer that is the index of the last matched object or -1 if no match was found
+     * @since 2.5.0
      */
-    public static void println(Object self, PrintWriter out) {
-        if (out == null) {
-            out = new PrintWriter(System.out);
-        }
-        out.println(FormatHelper.toString(self));
+    public static <T> int findLastIndexOf(Iterable<T> self, int startIndex, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return findLastIndexOf(self.iterator(), startIndex, condition);
     }
 
+    //--------------------------------------------------------------------------
+    // findResult
+
     /**
-     * Printf to the standard output stream.
+     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result obtained from calling the closure, otherwise returns null.
+     * <p>
+     * <pre class="groovyTestCase">
+     * int[] numbers = [1, 2, 3]
+     * assert numbers.findResult { if(it {@code >} 1) return it } == 2
+     * assert numbers.findResult { if(it {@code >} 4) return it } == null
+     * </pre>
      *
-     * @param self   any Object
-     * @param format a format string
-     * @param values values referenced by the format specifiers in the format string
-     * @since 1.0
+     * @param self      an Object with an iterator returning its values
+     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result of the closure
+     * @since 1.7.5
      */
-    public static void printf(Object self, String format, Object[] values) {
-        if (self instanceof PrintStream)
-            ((PrintStream)self).printf(format, values);
-        else
-            System.out.printf(format, values);
+    public static Object findResult(Object self, Closure condition) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); ) {
+            Object value = iter.next();
+            Object result = condition.call(value);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
     }
 
     /**
-     * Printf 0 or more values to the standard output stream using a format string.
-     * This method delegates to the owner to execute the method.
+     * Treats the object as iterable, iterating through the values it represents and returns the first non-null value, otherwise returns null.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Foo {
+     *     List items
+     *     Iterator iterator() {
+     *         items.iterator()
+     *     }
+     * }
+     * assert new Foo(items: [null, 2, 4]).findResult() == 2
+     * assert new Foo(items: [null, null]).findResult() == null
+     * </pre>
      *
-     * @param self   a generated closure
-     * @param format a format string
-     * @param values values referenced by the format specifiers in the format string
-     * @since 3.0.0
+     * @param self      an Object with an iterator returning its values
+     * @return the first non-null result of the closure
+     * @since 4.0.9
      */
-    public static void printf(Closure self, String format, Object[] values) {
-        Object owner = getClosureOwner(self);
-        Object[] newValues = new Object[values.length + 1];
-        newValues[0] = format;
-        System.arraycopy(values, 0, newValues, 1, values.length);
-        InvokerHelper.invokeMethod(owner, "printf", newValues);
+    public static Object findResult(Object self) {
+        return findResult(self, Closure.IDENTITY);
     }
 
     /**
-     * Printf a value to the standard output stream using a format string.
-     * This method delegates to the owner to execute the method.
+     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result obtained from calling the closure, otherwise returns the defaultResult.
+     * <p>
+     * <pre class="groovyTestCase">
+     * int[] numbers = [1, 2, 3]
+     * assert numbers.findResult(5) { if(it {@code >} 1) return it } == 2
+     * assert numbers.findResult(5) { if(it {@code >} 4) return it } == 5
+     * </pre>
      *
-     * @param self   a generated closure
-     * @param format a format string
-     * @param value  value referenced by the format specifier in the format string
-     * @since 3.0.0
+     * @param self          an Object with an iterator returning its values
+     * @param defaultResult an Object that should be returned if all closure results are null
+     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result of the closure, otherwise the default value
+     * @since 1.7.5
      */
-    public static void printf(Closure self, String format, Object value) {
-        Object owner = getClosureOwner(self);
-        Object[] newValues = new Object[2];
-        newValues[0] = format;
-        newValues[1] = value;
-        InvokerHelper.invokeMethod(owner, "printf", newValues);
+    public static Object findResult(Object self, Object defaultResult, Closure condition) {
+        Object result = findResult(self, condition);
+        if (result == null) return defaultResult;
+        return result;
     }
 
     /**
-     * Prints a formatted string using the specified format string and arguments.
+     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result, otherwise returns the defaultResult.
      * <p>
-     * Examples:
-     * <pre>
-     *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
-     *     printf ( "Hello, %s!\n" , [ "Groovy" ])
-     *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
-     *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
-     *
-     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
-     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
-     *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
-     *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
-     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
-     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
-     *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
-     *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
+     * <pre class="groovyTestCase">
+     * class Foo {
+     *     List items
+     *     Iterator iterator() {
+     *         items.iterator()
+     *     }
+     * }
+     * assert new Foo(items: [null, 2, 4]).findResult(5) == 2
+     * assert new Foo(items: [null, null]).findResult(5) == 5
      * </pre>
      *
-     * @param self   any Object
-     * @param format A format string
-     * @param arg    Argument which is referenced by the format specifiers in the format
-     *               string.  The type of <code>arg</code> should be one of Object[], List,
-     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
-     * @since 1.0
+     * @param self          an Object with an iterator returning its values
+     * @param defaultResult an Object that should be returned if all elements are null
+     * @return the first non-null element, otherwise the default value
+     * @since 4.0.9
      */
-    public static void printf(Object self, String format, Object arg) {
-        if (self instanceof PrintStream)
-            printf((PrintStream) self, format, arg);
-        else if (self instanceof Writer)
-            printf((Writer) self, format, arg);
-        else
-            printf(System.out, format, arg);
-    }
-
-    private static void printf(PrintStream self, String format, Object arg) {
-        self.print(sprintf(self, format, arg));
-    }
-
-    private static void printf(Writer self, String format, Object arg) {
-        try {
-            self.write(sprintf(self, format, arg));
-        } catch (IOException e) {
-            printf(System.out, format, arg);
-        }
+    public static Object findResult(Object self, Object defaultResult) {
+        Object result = findResult(self, Closure.IDENTITY);
+        if (result == null) return defaultResult;
+        return result;
     }
 
     /**
-     * Sprintf to a string.
+     * Iterates through the Iterator calling the given closure condition for each item but stopping once the first non-null
+     * result is found and returning that result. If all are null, the defaultResult is returned.
+     * <p>
+     * Examples:
+     * <pre class="groovyTestCase">
+     * def iter = [1,2,3].iterator()
+     * assert "Found 2" == iter.findResult("default") { it {@code >} 1 ? "Found $it" : null }
+     * assert "default" == iter.findResult("default") { it {@code >} 3 ? "Found $it" : null }
+     * </pre>
      *
-     * @param self   any Object
-     * @param format a format string
-     * @param values values referenced by the format specifiers in the format string
-     * @return the resulting formatted string
-     * @since 1.5.0
+     * @param self          an Iterator
+     * @param defaultResult an Object that should be returned if all closure results are null
+     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result from calling the closure, or the defaultValue
+     * @since 2.5.0
      */
-    public static String sprintf(Object self, String format, Object[] values) {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        PrintStream out = new PrintStream(outputStream);
-        out.printf(format, values);
-        return outputStream.toString();
+    public static <S, T, U extends T, V extends T> T findResult(Iterator<S> self, U defaultResult, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> condition) {
+        T result = findResult(self, condition);
+        if (result == null) return defaultResult;
+        return result;
     }
 
     /**
-     * Returns a formatted string using the specified format string and
-     * arguments.
+     * Iterates through the Iterator stopping once the first non-null
+     * result is found and returning that result. If all are null, the defaultResult is returned.
+     * <p>
+     * Examples:
+     * <pre class="groovyTestCase">
+     * assert [null, 1, 2].iterator().findResult('default') == 1
+     * assert [null, null].findResult('default') == 'default'
+     * </pre>
      *
-     * @param self   any Object
-     * @param format A format string
-     * @param arg    Argument which is referenced by the format specifiers in the format
-     *               string.  The type of <code>arg</code> should be one of Object[], List,
-     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
-     * @return the resulting printf'd string
-     * @since 1.5.0
+     * @param self          an Iterator
+     * @param defaultResult an Object that should be returned if all elements are null
+     * @return the first non-null result from the iterator, or the defaultValue
+     * @since 4.0.9
      */
-    public static String sprintf(Object self, String format, Object arg) {
-        if (arg instanceof Object[]) {
-            return sprintf(self, format, (Object[]) arg);
-        }
-        if (arg instanceof List) {
-            return sprintf(self, format, ((List) arg).toArray());
-        }
-        if (!arg.getClass().isArray()) {
-            Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
-            o[0] = arg;
-            return sprintf(self, format, o);
-        }
+    public static <T, U extends T, V extends T> T findResult(Iterator<U> self, V defaultResult) {
+        T result = (T) findResult(self, Closure.IDENTITY);
+        return result == null ? defaultResult : result;
+    }
 
-        Object[] ans;
-        String elemType = arg.getClass().getName();
-        switch (elemType) {
-            case "[I":
-                int[] ia = (int[]) arg;
-                ans = new Integer[ia.length];
-                for (int i = 0; i < ia.length; i++) {
-                    ans[i] = ia[i];
-                }
-                break;
-            case "[C":
-                char[] ca = (char[]) arg;
-                ans = new Character[ca.length];
-                for (int i = 0; i < ca.length; i++) {
-                    ans[i] = ca[i];
-                }
-                break;
-            case "[Z": {
-                boolean[] ba = (boolean[]) arg;
-                ans = new Boolean[ba.length];
-                for (int i = 0; i < ba.length; i++) {
-                    ans[i] = ba[i];
-                }
-                break;
-            }
-            case "[B": {
-                byte[] ba = (byte[]) arg;
-                ans = new Byte[ba.length];
-                for (int i = 0; i < ba.length; i++) {
-                    ans[i] = ba[i];
-                }
-                break;
+    /**
+     * Iterates through the Iterator calling the given closure condition for each item but stopping once the first non-null
+     * result is found and returning that result. If all results are null, null is returned.
+     *
+     * @param self      an Iterator
+     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result from calling the closure, or null
+     * @since 2.5.0
+     */
+    public static <T, U> T findResult(Iterator<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> condition) {
+        while (self.hasNext()) {
+            U next = self.next();
+            T result = condition.call(next);
+            if (result != null) {
+                return result;
             }
-            case "[S":
-                short[] sa = (short[]) arg;
-                ans = new Short[sa.length];
-                for (int i = 0; i < sa.length; i++) {
-                    ans[i] = sa[i];
-                }
-                break;
-            case "[F":
-                float[] fa = (float[]) arg;
-                ans = new Float[fa.length];
-                for (int i = 0; i < fa.length; i++) {
-                    ans[i] = fa[i];
-                }
-                break;
-            case "[J":
-                long[] la = (long[]) arg;
-                ans = new Long[la.length];
-                for (int i = 0; i < la.length; i++) {
-                    ans[i] = la[i];
-                }
-                break;
-            case "[D":
-                double[] da = (double[]) arg;
-                ans = new Double[da.length];
-                for (int i = 0; i < da.length; i++) {
-                    ans[i] = da[i];
-                }
-                break;
-            default:
-                throw new RuntimeException("sprintf(String," + arg + ")");
         }
-        return sprintf(self, format, ans);
+        return null;
     }
 
-    //-------------------------------------------------------------------------
-    // isCase/isNotCase
-
     /**
-     * Method for overloading the behavior of the 'case' method in switch statements.
-     * The default implementation handles arrays types but otherwise simply delegates
-     * to Object#equals, but this may be overridden for other types. In this example:
-     * <pre> switch( a ) {
-     *   case b: //some code
-     * }</pre>
-     * "some code" is called when <code>b.isCase( a )</code> returns
-     * <code>true</code>.
+     * Iterates through the Iterator stopping once the first non-null
+     * result is found and returning that result. If all results are null, null is returned.
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the switchValue is deemed to be equal to the caseValue
-     * @since 1.0
+     * @param self      an Iterator
+     * @return the first non-null result from the iterator, or null
+     * @since 4.0.9
      */
-    public static boolean isCase(Object caseValue, Object switchValue) {
-        if (caseValue.getClass().isArray()) {
-            return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
-        }
-        return caseValue.equals(switchValue);
+    public static <T> T findResult(Iterator<T> self) {
+        return (T) findResult(self, Closure.IDENTITY);
     }
 
     /**
-     * Special 'Case' implementation for Class, which allows testing
-     * whether some switch value is assignable from the given case class.
-     *
-     * If the switch value is an object, {@code isCase} will return true if the
-     * switch value is assignment compatible with the class (case value),
-     * i.e.&nbsp;is an {@code instanceof} the class, for example:
+     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
+     * result is found and returning that result. If all are null, the defaultResult is returned.
+     * <p>
+     * Examples:
      * <pre class="groovyTestCase">
-     * def someList = []
-     * switch (someList) {
-     *   case List:
-     *     assert true : 'is a list'
-     *     break
-     *   case Map:
-     *     assert false : 'is not a Map'
-     *     break
-     *   default:
-     *     assert false : 'should never get here'
-     *     break
-     * }
+     * def list = [1,2,3]
+     * assert "Found 2" == list.findResult("default") { it {@code >} 1 ? "Found $it" : null }
+     * assert "default" == list.findResult("default") { it {@code >} 3 ? "Found $it" : null }
      * </pre>
      *
-     * If the switch value is a class, {@code isCase} will return true if the
-     * switch value is assignable from the given class (case value), i.e.&nbsp;the case class
-     * is the same as, or a superclass, or a super-interface of the switch class, for example:
+     * @param self          an Iterable
+     * @param defaultResult an Object that should be returned if all closure results are null
+     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result from calling the closure, or the defaultValue
+     * @since 2.5.0
+     */
+    public static <S, T, U extends T, V extends T> T findResult(Iterable<S> self, U defaultResult, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> condition) {
+        T result = findResult(self, condition);
+        if (result == null) return defaultResult;
+        return result;
+    }
+
+    /**
+     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
+     * result is found and returning that result. If all are null, the defaultResult is returned.
+     * <p>
+     * Examples:
      * <pre class="groovyTestCase">
-     * switch (ArrayList) {
-     *   case List:
-     *     assert true : 'is a list'
-     *     break
-     *   case Map:
-     *     assert false : 'is not a Map'
-     *     break
-     *   default:
-     *     assert false : 'should never get here'
-     *     break
-     * }
+     * assert [null, 1, 2].findResult('default') == 1
+     * assert [null, null].findResult('default') == 'default'
      * </pre>
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the switchValue is deemed to be assignable from the given class
-     * @since 1.0
+     * @param self          an Iterable
+     * @param defaultResult an Object that should be returned if all elements in the iterable are null
+     * @return the first non-null element from the iterable, or the defaultValue
+     * @since 4.0.9
      */
-    @SuppressWarnings("unchecked")
-    public static boolean isCase(Class caseValue, Object switchValue) {
-        if (switchValue instanceof Class) {
-            Class val = (Class) switchValue;
-            return caseValue.isAssignableFrom(val);
-        }
-        return caseValue.isInstance(switchValue);
+    public static <T, U extends T, V extends T> T findResult(Iterable<U> self, V defaultResult) {
+        T result = (T) findResult(self, Closure.IDENTITY);
+        if (result == null) return defaultResult;
+        return result;
     }
 
     /**
-     * 'Case' implementation for collections which tests if the 'switch'
-     * operand is contained in any of the 'case' values.
-     * For example:
-     * <pre class="groovyTestCase">switch( 3 ) {
-     *   case [1,3,5]:
-     *     assert true
-     *     break
-     *   default:
-     *     assert false
-     * }</pre>
+     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
+     * result is found and returning that result. If all results are null, null is returned.
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the caseValue is deemed to contain the switchValue
-     * @see java.util.Collection#contains(java.lang.Object)
-     * @since 1.0
+     * @param self      an Iterable
+     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
+     * @return the first non-null result from calling the closure, or null
+     * @since 2.5.0
      */
-    public static boolean isCase(Collection caseValue, Object switchValue) {
-        return caseValue.contains(switchValue);
+    public static <T, U> T findResult(Iterable<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> condition) {
+        return findResult(self.iterator(), condition);
     }
 
     /**
-     * 'Case' implementation for iterable types which tests if the 'switch'
-     * operand is contained in any of the 'case' values.
-     * For example:
-     * <pre class="groovyTestCase">Iterable it = {[1,3,5].iterator()}
-     * switch( 3 ) {
-     *   case it:
-     *     assert true
-     *     break
-     *   default:
-     *     assert false
-     * }
-     *
-     * //GROOVY-7919
-     * assert 1 in it
-     * assert 2 !in it
-     * </pre>
+     * Iterates through the Iterable stopping once the first non-null
+     * result is found and returning that result. If all results are null, null is returned.
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the caseValue is deemed to contain the switchValue
-     * @see #contains(Iterable,Object)
-     * @since 5.0.0
+     * @param self      an Iterable
+     * @return the first non-null element from the iterable, or null
+     * @since 4.0.9
      */
-    public static boolean isCase(Iterable caseValue, Object switchValue) {
-        return contains(caseValue, switchValue);
+    public static <T> T findResult(Iterable<T> self) {
+        return (T) findResult(self.iterator(), Closure.IDENTITY);
     }
 
     /**
-     * 'Case' implementation for maps which tests the groovy truth
-     * value obtained using the 'switch' operand as key.
-     * For example:
-     * <pre class="groovyTestCase">switch( 'foo' ) {
-     *   case [foo:true, bar:false]:
-     *     assert true
-     *     break
-     *   default:
-     *     assert false
-     * }</pre>
+     * Returns the first non-null closure result found by passing each map entry to the closure, otherwise null is returned.
+     * If the closure takes two parameters, the entry key and value are passed.
+     * If the closure takes one parameter, the Map.Entry object is passed.
+     * <pre class="groovyTestCase">
+     * assert "Found b:3" == [a:1, b:3].findResult { if (it.value == 3) return "Found ${it.key}:${it.value}" }
+     * assert null == [a:1, b:3].findResult { if (it.value == 9) return "Found ${it.key}:${it.value}" }
+     * assert "Found a:1" == [a:1, b:3].findResult { k, v {@code ->} if (k.size() + v == 2) return "Found $k:$v" }
+     * </pre>
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return the groovy truth value from caseValue corresponding to the switchValue key
-     * @since 1.7.6
+     * @param self      a Map
+     * @param condition a 1 or 2 arg Closure that returns a non-null value when processing should stop and a value should be returned
+     * @return the first non-null result collected by calling the closure, or null if no such result was found
+     * @since 1.7.5
      */
-    public static boolean isCase(Map caseValue, Object switchValue) {
-        return DefaultTypeTransformation.castToBoolean(caseValue.get(switchValue));
+    public static <T, K, V> T findResult(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> condition) {
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            T result = callClosureForMapEntry(condition, entry);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
     }
 
     /**
-     * Special 'case' implementation for all numbers, which delegates to the
-     * <code>compareTo()</code> method for comparing numbers of different
-     * types.
+     * Returns the first non-null closure result found by passing each map entry to the closure, otherwise the defaultResult is returned.
+     * If the closure takes two parameters, the entry key and value are passed.
+     * If the closure takes one parameter, the Map.Entry object is passed.
+     * <pre class="groovyTestCase">
+     * assert "Found b:3" == [a:1, b:3].findResult("default") { if (it.value == 3) return "Found ${it.key}:${it.value}" }
+     * assert "default" == [a:1, b:3].findResult("default") { if (it.value == 9) return "Found ${it.key}:${it.value}" }
+     * assert "Found a:1" == [a:1, b:3].findResult("default") { k, v {@code ->} if (k.size() + v == 2) return "Found $k:$v" }
+     * </pre>
      *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the numbers are deemed equal
-     * @since 1.5.0
+     * @param self          a Map
+     * @param defaultResult an Object that should be returned if all closure results are null
+     * @param condition     a 1 or 2 arg Closure that returns a non-null value when processing should stop and a value should be returned
+     * @return the first non-null result collected by calling the closure, or the defaultResult if no such result was found
+     * @since 1.7.5
      */
-    public static boolean isCase(Number caseValue, Number switchValue) {
-        return NumberMath.compareTo(caseValue, switchValue) == 0;
+    public static <T, U extends T, V extends T, A, B> T findResult(Map<A, B> self, U defaultResult, @ClosureParams(MapEntryOrKeyValue.class) Closure<V> condition) {
+        T result = findResult(self, condition);
+        if (result == null) return defaultResult;
+        return result;
     }
 
-    /**
-     * @since 4.0.0
-     */
-    public static boolean isNotCase(Number caseValue, Number switchValue) {
-        return !isCase(caseValue, switchValue);
-    }
+    //--------------------------------------------------------------------------
+    // findResults
 
     /**
-     * @since 4.0.0
+     * Iterates through the Iterable transforming items using the supplied closure
+     * and collecting any non-null results.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def list = [1,2,3]
+     * def result = list.findResults { it {@code >} 1 ? "Found $it" : null }
+     * assert result == ["Found 2", "Found 3"]
+     * </pre>
+     *
+     * @param self               an Iterable
+     * @param filteringTransform a Closure that should return either a non-null transformed value or null for items which should be discarded
+     * @return the list of non-null transformed values
+     * @since 2.2.0
      */
-    public static boolean isNotCase(Object caseValue, Object switchValue) {
-        return !isCase(caseValue, switchValue);
+    public static <T, U> Collection<T> findResults(Iterable<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> filteringTransform) {
+        return findResults(self.iterator(), filteringTransform);
     }
 
     /**
-     * @since 4.0.0
+     * Iterates through the Iterable collecting any non-null results.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert [1, null, 2, null, 3].findResults() == [1, 2, 3]
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return the list of non-null values
+     * @since 4.0.9
      */
-    public static boolean isNotCase(Class<?> caseValue, Object switchValue) {
-        return !isCase(caseValue, switchValue);
+    public static <T> Collection<T> findResults(Iterable<T> self) {
+        return findResults(self.iterator(), Closure.IDENTITY);
     }
 
     /**
-     * @since 4.0.0
+     * Iterates through the Iterator transforming items using the supplied closure
+     * and collecting any non-null results.
+     *
+     * @param self               an Iterator
+     * @param filteringTransform a Closure that should return either a non-null transformed value or null for items which should be discarded
+     * @return the list of non-null transformed values
+     * @since 2.5.0
      */
-    public static boolean isNotCase(Closure<?> caseValue, Object switchValue) {
-        return !caseValue.isCase(switchValue);
+    public static <T, U> Collection<T> findResults(Iterator<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> filteringTransform) {
+        List<T> result = new ArrayList<>();
+        while (self.hasNext()) {
+            U value = self.next();
+            T transformed = filteringTransform.call(value);
+            if (transformed != null) {
+                result.add(transformed);
+            }
+        }
+        return result;
     }
 
     /**
-     * @since 4.0.0
+     * Iterates through the Iterator collecting any non-null results.
+     *
+     * @param self an Iterator
+     * @return the list of non-null values
+     * @since 4.0.9
      */
-    public static boolean isNotCase(Collection<?> caseValue, Object switchValue) {
-        return !isCase(caseValue, switchValue);
+    public static <T> Collection<T> findResults(Iterator<T> self) {
+        return findResults(self, Closure.IDENTITY);
     }
 
     /**
-     * @since 4.0.0
+     * Iterates through the map transforming items using the supplied closure
+     * and collecting any non-null results.
+     * If the closure takes two parameters, the entry key and value are passed.
+     * If the closure takes one parameter, the Map.Entry object is passed.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def map = [a:1, b:2, hi:2, cat:3, dog:2]
+     * def result = map.findResults { k, v {@code ->} k.size() == v ? "Found $k:$v" : null }
+     * assert result == ["Found a:1", "Found hi:2", "Found cat:3"]
+     * </pre>
+     *
+     * @param self               a Map
+     * @param filteringTransform a 1 or 2 arg Closure that should return either a non-null transformed value or null for items which should be discarded
+     * @return the list of non-null transformed values
+     * @since 1.8.1
      */
-    public static boolean isNotCase(Map<?, ?>     caseValue, Object switchValue) {
-        return !isCase(caseValue, switchValue);
+    public static <T, K, V> Collection<T> findResults(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> filteringTransform) {
+        List<T> result = new ArrayList<>();
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            T transformed = callClosureForMapEntry(filteringTransform, entry);
+            if (transformed != null) {
+                result.add(transformed);
+            }
+        }
+        return result;
     }
 
     //--------------------------------------------------------------------------
+    // first
 
     /**
-     * Returns an iterator equivalent to this iterator with all duplicated items removed
-     * by using Groovy's default number-aware comparator. The original iterator will become
-     * exhausted of elements after determining the unique values. A new iterator
-     * for the unique values will be returned.
+     * Returns the first item from the List.
+     * <pre class="groovyTestCase">
+     * def list = [3, 4, 2]
+     * assert list.first() == 3
+     * // check original is unaltered
+     * assert list == [3, 4, 2]
+     * </pre>
      *
-     * @param self an Iterator
-     * @return a new Iterator of the unique items from the original iterator
+     * @param self a List
+     * @return the first item from the List
+     * @throws NoSuchElementException if you try to access first() for an empty List
      * @since 1.5.5
      */
-    public static <T> Iterator<T> unique(Iterator<T> self) {
-        return uniqueItems(new IteratorIterableAdapter<>(self)).listIterator();
+    public static <T> T first(List<T> self) {
+        if (self.isEmpty()) {
+            throw new NoSuchElementException("Cannot access first() element from an empty List");
+        }
+        return self.get(0);
     }
 
     /**
-     * Modifies this collection to remove all duplicated items, using Groovy's
-     * default number-aware comparator.
-     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     * Returns the first item from the Iterable.
+     * <pre class="groovyTestCase">
+     * def set = [3, 4, 2] as LinkedHashSet
+     * assert set.first() == 3
+     * // check original is unaltered
+     * assert set == [3, 4, 2] as Set
+     * </pre>
+     * The first element returned by the Iterable's iterator is returned.
+     * If the Iterable doesn't guarantee a defined order it may appear like
+     * a random element is returned.
      *
-     * @param self a collection
-     * @return the now modified collection
-     * @see #unique(Collection, boolean)
-     * @since 1.0
+     * @param self an Iterable
+     * @return the first item from the Iterable
+     * @throws NoSuchElementException if you try to access first() for an empty Iterable
+     * @since 1.8.7
      */
-    public static <T> Collection<T> unique(Collection<T> self) {
-        return unique(self, true);
+    public static <T> T first(Iterable<T> self) {
+        Iterator<T> iterator = self.iterator();
+        if (!iterator.hasNext()) {
+            throw new NoSuchElementException("Cannot access first() element from an empty Iterable");
+        }
+        return iterator.next();
     }
 
+    //--------------------------------------------------------------------------
+    // flatten
+
     /**
-     * Modifies this List to remove all duplicated items, using Groovy's
-     * default number-aware comparator.
-     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     * Flatten a Collection. This Collection and any nested arrays or
+     * collections have their contents (recursively) added to the new collection.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()</pre>
      *
-     * @param self a List
-     * @return the now modified List
-     * @see #unique(Collection, boolean)
-     * @since 2.4.0
+     * @param self a Collection to flatten
+     * @return a flattened Collection
+     * @since 1.6.0
      */
-    public static <T> List<T> unique(List<T> self) {
-        return (List<T>) unique((Collection<T>) self, true);
+    public static Collection<?> flatten(Collection<?> self) {
+        return flatten(self, createSimilarCollection(self));
     }
 
     /**
-     * Remove all duplicates from a given Collection using Groovy's default number-aware comparator.
-     * If mutate is true, it works by modifying the original object (and also returning it).
-     * If mutate is false, a new collection is returned leaving the original unchanged.
-     * <pre class="groovyTestCase">
-     * assert [1,3] == [1,3,3].unique()
-     * </pre>
-     * <pre class="groovyTestCase">
-     * def orig = [1, 3, 2, 3]
-     * def uniq = orig.unique(false)
-     * assert orig == [1, 3, 2, 3]
-     * assert uniq == [1, 3, 2]
-     * </pre>
+     * Flatten an Iterable. This Iterable and any nested arrays or
+     * collections have their contents (recursively) added to the new collection.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()</pre>
      *
-     * @param self a collection
-     * @param mutate false will cause a new list containing unique items from the collection to be created, true will mutate collections in place
-     * @return the now modified collection
-     * @since 1.8.1
+     * @param self an Iterable to flatten
+     * @return a flattened Collection
+     * @since 1.6.0
      */
-    public static <T> Collection<T> unique(Collection<T> self, boolean mutate) {
-        List<T> answer = uniqueItems(self);
-        if (mutate) {
-            self.clear();
-            self.addAll(answer);
-        }
-        return mutate ? self : answer ;
+    public static Collection<?> flatten(Iterable<?> self) {
+        return flatten(self, createSimilarCollection(self));
     }
 
-    private static <T> List<T> uniqueItems(Iterable<T> self) {
-        List<T> answer = new ArrayList<>();
-        for (T t : self) {
-            boolean duplicated = false;
-            for (T t2 : answer) {
-                if (coercedEquals(t, t2)) {
-                    duplicated = true;
-                    break;
-                }
-            }
-            if (!duplicated)
-                answer.add(t);
-        }
-        return answer;
+    /**
+     * Flatten a List. This List and any nested arrays or
+     * collections have their contents (recursively) added to the new List.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()</pre>
+     *
+     * @param self a List to flatten
+     * @return a flattened List
+     * @since 2.4.0
+     */
+    public static List<?> flatten(List<?> self) {
+        return (List<?>) flatten((Collection<?>) self);
     }
 
     /**
-     * Remove all duplicates from a given List using Groovy's default number-aware comparator.
-     * If mutate is true, it works by modifying the original object (and also returning it).
-     * If mutate is false, a new collection is returned leaving the original unchanged.
-     * <pre class="groovyTestCase">
-     * assert [1,3] == [1,3,3].unique()
-     * </pre>
+     * Flatten a Set. This Set and any nested arrays or
+     * collections have their contents (recursively) added to the new Set.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] as Set == ([1,[2,3],[[4]],[],5] as Set).flatten()</pre>
+     *
+     * @param self a Set to flatten
+     * @return a flattened Set
+     * @since 2.4.0
+     */
+    public static Set<?> flatten(Set<?> self) {
+        return (Set<?>) flatten((Collection<?>) self);
+    }
+
+    /**
+     * Flatten a SortedSet. This SortedSet and any nested arrays or
+     * collections have their contents (recursively) added to the new SortedSet.
      * <pre class="groovyTestCase">
-     * def orig = [1, 3, 2, 3]
-     * def uniq = orig.unique(false)
-     * assert orig == [1, 3, 2, 3]
-     * assert uniq == [1, 3, 2]
+     * Set nested = [[0,1],[2],3,[4],5]
+     * SortedSet sorted = new TreeSet({ a, b {@code ->} (a instanceof List ? a[0] : a) {@code <=>} (b instanceof List ? b[0] : b) } as Comparator)
+     * sorted.addAll(nested)
+     * assert [0,1,2,3,4,5] as SortedSet == sorted.flatten()
      * </pre>
      *
-     * @param self a List
-     * @param mutate false will cause a new List containing unique items from the List to be created, true will mutate List in place
-     * @return the now modified List
+     * @param self a SortedSet to flatten
+     * @return a flattened SortedSet
      * @since 2.4.0
      */
-    public static <T> List<T> unique(List<T> self, boolean mutate) {
-        return (List<T>) unique((Collection<T>) self, mutate);
+    public static SortedSet<?> flatten(SortedSet<?> self) {
+        return (SortedSet<?>) flatten((Collection<?>) self);
+    }
+
+    private static Collection flatten(Iterable elements, Collection addTo) {
+        for (Object element : elements) {
+            if (element instanceof Collection) {
+                flatten((Collection) element, addTo);
+            } else if (element != null && element.getClass().isArray()) {
+                flatten(DefaultTypeTransformation.arrayAsCollection(element), addTo);
+            } else {
+                // found a leaf
+                addTo.add(element);
+            }
+        }
+        return addTo;
     }
 
     /**
-     * Provides a method that compares two comparables using Groovy's
-     * default number aware comparator.
+     * Flatten an Iterable. This Iterable and any nested arrays or
+     * collections have their contents (recursively) added to the new collection.
+     * For any non-Array, non-Collection object which represents some sort
+     * of collective type, the supplied closure should yield the contained items;
+     * otherwise, the closure should just return any element which corresponds to a leaf.
      *
-     * @param self a Comparable
-     * @param other another Comparable
-     * @return a -ve number, 0 or a +ve number according to Groovy's compareTo contract
+     * @param self an Iterable
+     * @param flattenUsing a closure to determine how to flatten non-Array, non-Collection elements
+     * @return a flattened Collection
      * @since 1.6.0
      */
-    public static int numberAwareCompareTo(Comparable self, Comparable other) {
-        return COMPARABLE_NUMBER_AWARE_COMPARATOR.compare(self, other);
+    public static <T> Collection<T> flatten(Iterable<T> self, Closure<? extends T> flattenUsing) {
+        return flatten(self, createSimilarCollection(self), flattenUsing);
+    }
+
+    private static <T> Collection<T> flatten(Iterable elements, Collection<T> addTo, Closure<? extends T> flattenUsing) {
+        for (Object element : elements) {
+            if (element instanceof Collection) {
+                flatten((Collection) element, addTo, flattenUsing);
+            } else if (element != null && element.getClass().isArray()) {
+                flatten(DefaultTypeTransformation.arrayAsCollection(element), addTo, flattenUsing);
+            } else {
+                T flattened = flattenUsing.call(new Object[]{element});
+                boolean returnedSelf = flattened == element;
+                if (!returnedSelf && flattened instanceof Collection) {
+                    List<?> list = toList((Iterable<?>) flattened);
+                    if (list.size() == 1 && list.get(0) == element) {
+                        returnedSelf = true;
+                    }
+                }
+                if (flattened instanceof Collection && !returnedSelf) {
+                    flatten((Collection) flattened, addTo, flattenUsing);
+                } else {
+                    addTo.add(flattened);
+                }
+            }
+        }
+        return addTo;
     }
 
+    //--------------------------------------------------------------------------
+    // get
+
     /**
-     * Returns an iterator equivalent to this iterator but with all duplicated items
-     * removed by using a Closure to determine duplicate (equal) items.
-     * The original iterator will be fully processed after the call.
-     * <p>
-     * If the closure takes a single parameter, the argument passed will be each element,
-     * and the closure should return a value used for comparison (either using
-     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
-     * If the closure takes two parameters, two items from the Iterator
-     * will be passed as arguments, and the closure should return an
-     * int value (with 0 indicating the items are not unique).
+     * Looks up an item in a Map for the given key and returns the corresponding value.
+     * If there is no entry for the given key return instead the default value and
+     * also add the key and default value to the map.
+     * <pre class="groovyTestCase">
+     * def map=[:]
+     * map.get("a", []) &lt;&lt; 5
+     * assert map == [a:[5]]
+     * </pre>
+     * For a method which doesn't mutate the map, consider instead using {@link Map#getOrDefault(Object, Object)}
+     * or consider using Groovy's {@link MapWithDefault} often instantiated using {@link #withDefault(Map, Closure)}
+     * or with more options {@link #withDefault(Map, boolean, boolean, Closure)}.
      *
-     * @param self      an Iterator
-     * @param condition a Closure used to determine unique items
-     * @return the modified Iterator
-     * @since 1.5.5
+     * @param map          a Map
+     * @param key          the key to look up the value
+     * @param defaultValue the value to return and add to the map for this key if
+     *                     there is no entry for the given key
+     * @return the value of the given key or the default value, added to the map if the
+     *         key did not exist
+     * @since 1.0
      */
-    public static <T> Iterator<T> unique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
-        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
-                ? new OrderBy<>(condition, true)
-                : new ClosureComparator<>(condition);
-        return unique(self, comparator);
+    public static <K, V> V get(Map<K, V> map, K key, V defaultValue) {
+        if (!map.containsKey(key)) {
+            map.put(key, defaultValue);
+        }
+        return map.get(key);
     }
 
+    //--------------------------------------------------------------------------
+    // getAt
+
     /**
-     * A convenience method for making a collection unique using a Closure
-     * to determine duplicate (equal) items.
-     * <p>
-     * If the closure takes a single parameter, the
-     * argument passed will be each element, and the closure
-     * should return a value used for comparison (either using
-     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
-     * If the closure takes two parameters, two items from the collection
-     * will be passed as arguments, and the closure should return an
-     * int value (with 0 indicating the items are not unique).
-     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
-     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b {@code ->} a {@code <=>} b }</pre>
+     * Allows the subscript operator to be used to lookup dynamic property values.
+     * <code>bean[somePropertyNameExpression]</code>. The normal property notation
+     * of groovy is neater and more concise but only works with compile-time known
+     * property names.
      *
-     * @param self    a Collection
-     * @param closure a 1 or 2 arg Closure used to determine unique items
-     * @return self   without any duplicates
-     * @see #unique(Collection, boolean, Closure)
+     * @param self     the object to act upon
+     * @param property the property name of interest
+     * @return the property value
      * @since 1.0
      */
-    public static <T> Collection<T> unique(Collection<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return unique(self, true, closure);
+    public static Object getAt(Object self, String property) {
+        return InvokerHelper.getProperty(self, property);
     }
 
     /**
-     * A convenience method for making a List unique using a Closure
-     * to determine duplicate (equal) items.
-     * <p>
-     * If the closure takes a single parameter, the
-     * argument passed will be each element, and the closure
-     * should return a value used for comparison (either using
-     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
-     * If the closure takes two parameters, two items from the List
-     * will be passed as arguments, and the closure should return an
-     * int value (with 0 indicating the items are not unique).
-     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
-     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b {@code ->} a {@code <=>} b }</pre>
+     * Support the range subscript operator for a List.
+     * <pre class="groovyTestCase">def list = [1, "a", 4.5, true]
+     * assert list[1..2] == ["a", 4.5]</pre>
      *
-     * @param self    a List
-     * @param closure a 1 or 2 arg Closure used to determine unique items
-     * @return self   without any duplicates
-     * @see #unique(Collection, boolean, Closure)
-     * @since 2.4.0
+     * @param self  a List
+     * @param range a Range indicating the items to get
+     * @return a new list instance based on range borders
+     *
+     * @since 1.0
      */
-    public static <T> List<T> unique(List<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return (List<T>) unique((Collection<T>) self, true, closure);
+    public static <T> List<T> getAt(List<T> self, Range range) {
+        RangeInfo info = subListBorders(self.size(), range);
+
+        List<T> subList = self.subList(info.from, info.to);
+        if (info.reverse) {
+            subList = reverse(subList);
+        }
+
+        // trying to guess the concrete list type and create a new instance from it
+        List<T> answer = createSimilarList(self, subList.size());
+        answer.addAll(subList);
+
+        return answer;
     }
 
     /**
-     * A convenience method for making a collection unique using a Closure to determine duplicate (equal) items.
-     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
-     * <p>
-     * If the closure takes a single parameter, each element from the Collection will be passed to the closure. The closure
-     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
-     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
-     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
-     * <pre class="groovyTestCase">
-     * def orig = [1, 3, 4, 5]
-     * def uniq = orig.unique(false) { it % 2 }
-     * assert orig == [1, 3, 4, 5]
-     * assert uniq == [1, 4]
-     * </pre>
-     * <pre class="groovyTestCase">
-     * def orig = [2, 3, 3, 4]
-     * def uniq = orig.unique(false) { a, b {@code ->} a {@code <=>} b }
-     * assert orig == [2, 3, 3, 4]
-     * assert uniq == [2, 3, 4]
-     * </pre>
+     * Select a List of items from an eager or lazy List using a Collection to
+     * identify the indices to be selected.
+     * <pre class="groovyTestCase">def list = [].withDefault { 42 }
+     * assert list[1,0,2] == [42, 42, 42]</pre>
      *
-     * @param self    a Collection
-     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
-     * @param closure a 1 or 2 arg Closure used to determine unique items
-     * @return self   without any duplicates
-     * @since 1.8.1
+     * @param self    a ListWithDefault
+     * @param indices a Collection of indices
+     *
+     * @return a new eager or lazy list of the values at the given indices
      */
-    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        // use a comparator of one item or two
-        int params = closure.getMaximumNumberOfParameters();
-        if (params == 1) {
-            self = unique(self, mutate, new OrderBy<>(closure, true));
-        } else {
-            self = unique(self, mutate, new ClosureComparator<>(closure));
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> getAt(ListWithDefault<T> self, Collection indices) {
+        List<T> answer = ListWithDefault.newInstance(new ArrayList<>(indices.size()), self.isLazyDefaultValues(), self.getInitClosure());
+        for (Object value : indices) {
+            if (value instanceof Collection) {
+                answer.addAll((List<T>) InvokerHelper.invokeMethod(self, "getAt", value));
+            } else {
+                int idx = normaliseIndex(DefaultTypeTransformation.intUnbox(value), self.size());
+                answer.add(self.getAt(idx));
+            }
         }
-        return self;
+        return answer;
     }
 
     /**
-     * A convenience method for making a List unique using a Closure to determine duplicate (equal) items.
-     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
-     * <p>
-     * If the closure takes a single parameter, each element from the List will be passed to the closure. The closure
-     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
-     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
-     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
-     * <pre class="groovyTestCase">
-     * def orig = [1, 3, 4, 5]
-     * def uniq = orig.unique(false) { it % 2 }
-     * assert orig == [1, 3, 4, 5]
-     * assert uniq == [1, 4]
-     * </pre>
-     * <pre class="groovyTestCase">
-     * def orig = [2, 3, 3, 4]
-     * def uniq = orig.unique(false) { a, b {@code ->} a {@code <=>} b }
-     * assert orig == [2, 3, 3, 4]
-     * assert uniq == [2, 3, 4]
-     * </pre>
+     * Support the range subscript operator for an eager or lazy List.
+     * <pre class="groovyTestCase">def list = [].withDefault { 42 }
+     * assert list[1..2] == [null, 42]</pre>
      *
-     * @param self    a List
-     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
-     * @param closure a 1 or 2 arg Closure used to determine unique items
-     * @return self   without any duplicates
-     * @since 2.4.0
-     */
-    public static <T> List<T> unique(List<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return (List<T>) unique((Collection<T>) self, mutate, closure);
-    }
-
-    /**
-     * Returns an iterator equivalent to this iterator with all duplicated
-     * items removed by using the supplied comparator. The original iterator
-     * will be exhausted upon returning.
+     * @param self  a ListWithDefault
+     * @param range a Range indicating the items to get
      *
-     * @param self an Iterator
-     * @param comparator a Comparator
-     * @return the modified Iterator
-     * @since 1.5.5
+     * @return a new eager or lazy list instance based on range borders
      */
-    public static <T> Iterator<T> unique(Iterator<T> self, Comparator<? super T> comparator) {
-        return uniqueItems(new IteratorIterableAdapter<>(self), comparator).listIterator();
-    }
-
-    private static final class IteratorIterableAdapter<T> implements Iterable<T> {
-        private final Iterator<T> self;
+    public static <T> List<T> getAt(ListWithDefault<T> self, Range range) {
+        RangeInfo info = subListBorders(self.size(), range);
 
-        private IteratorIterableAdapter(Iterator<T> self) {
-            this.self = self;
+        // if a positive index is accessed not initialized so far
+        // initialization up to that index takes place
+        if (self.size() < info.to) {
+            self.get(info.to - 1);
         }
 
-        @Override
-        public Iterator<T> iterator() {
-            return self;
+        List<T> answer = self.subList(info.from, info.to);
+        if (info.reverse) {
+            answer =  ListWithDefault.newInstance(reverse(answer), self.isLazyDefaultValues(), self.getInitClosure());
+        } else {
+            // instead of using the SubList backed by the parent list, a new ArrayList instance is used
+            answer =  ListWithDefault.newInstance(new ArrayList<>(answer), self.isLazyDefaultValues(), self.getInitClosure());
         }
+
+        return answer;
     }
 
     /**
-     * Remove all duplicates from a given Collection.
-     * Works on the original object (and also returns it).
-     * The order of members in the Collection are compared by the given Comparator.
-     * For each duplicate, the first member which is returned
-     * by the given Collection's iterator is retained, but all other ones are removed.
-     * The given Collection's original order is preserved.
-     * <p>
+     * Support the range subscript operator for an eager or lazy List.
      * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
+     * def list = [true, 1, 3.4].withDefault{ 42 }
+     * {@code assert list[0..<0] == []}
+     * </pre>
      *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     * @param self  a ListWithDefault
+     * @param range a Range indicating the items to get
      *
-     * def list = [a, b, c, d]
-     * List list2 = list.unique(new PersonComparator())
-     * assert( list2 == list {@code &&} list == [a, b, c] )
-     * </pre>
+     * @return a new list instance based on range borders
      *
-     * @param self       a Collection
-     * @param comparator a Comparator
-     * @return self      the now modified collection without duplicates
-     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
-     * @since 1.0
      */
-    public static <T> Collection<T> unique(Collection<T> self, Comparator<? super T> comparator) {
-        return unique(self, true, comparator) ;
+    public static <T> List<T> getAt(ListWithDefault<T> self, EmptyRange range) {
+        return ListWithDefault.newInstance(new ArrayList<>(), self.isLazyDefaultValues(), self.getInitClosure());
     }
 
     /**
-     * Remove all duplicates from a given List.
-     * Works on the original object (and also returns it).
-     * The order of members in the List are compared by the given Comparator.
-     * For each duplicate, the first member which is returned
-     * by the given List's iterator is retained, but all other ones are removed.
-     * The given List's original order is preserved.
-     * <p>
+     * Support the range subscript operator for a List.
      * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
+     * def list = [true, 1, 3.4]
+     * {@code assert list[0..<0] == []}
+     * </pre>
      *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     * @param self  a List
+     * @param range a Range indicating the items to get
+     * @return a new list instance based on range borders
      *
-     * def list = [a, b, c, d]
-     * List list2 = list.unique(new PersonComparator())
-     * assert( list2 == list {@code &&} list == [a, b, c] )
-     * </pre>
+     * @since 1.0
+     */
+    public static <T> List<T> getAt(List<T> self, EmptyRange range) {
+        return createSimilarList(self, 0);
+    }
+
+    /**
+     * Select a List of items from a List using a Collection to
+     * identify the indices to be selected.
+     * <pre class="groovyTestCase">def list = [true, 1, 3.4, false]
+     * assert list[1,0,2] == [1, true, 3.4]</pre>
      *
-     * @param self       a List
-     * @param comparator a Comparator
-     * @return self      the now modified List without duplicates
-     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
-     * @since 2.4.0
+     * @param self    a List
+     * @param indices a Collection of indices
+     * @return a new list of the values at the given indices
+     * @since 1.0
      */
-    public static <T> List<T> unique(List<T> self, Comparator<? super T> comparator) {
-        return (List<T>) unique((Collection<T>) self, true, comparator);
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> getAt(List<T> self, Collection indices) {
+        List<T> answer = new ArrayList<>(indices.size());
+        for (Object value : indices) {
+            if (value instanceof Collection) {
+                answer.addAll(getAt(self, (Collection) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.add(getAt(self, idx));
+            }
+        }
+        return answer;
     }
 
     /**
-     * Remove all duplicates from a given Collection.
-     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new collection is returned.
-     * The order of members in the Collection are compared by the given Comparator.
-     * For each duplicate, the first member which is returned
-     * by the given Collection's iterator is retained, but all other ones are removed.
-     * The given Collection's original order is preserved.
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
+     * Support the subscript operator for a List.
+     * <pre class="groovyTestCase">def list = [2, "a", 5.3]
+     * assert list[1] == "a"</pre>
      *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
-     *
-     * def list = [a, b, c, d]
-     * List list2 = list.unique(false, new PersonComparator())
-     * assert( list2 != list {@code &&} list2 == [a, b, c] )
-     * </pre>
-     *
-     * @param self       a Collection
-     * @param mutate     false will always cause a new collection to be created, true will mutate collections in place
-     * @param comparator a Comparator
-     * @return self      the collection without duplicates
-     * @since 1.8.1
+     * @param self a List
+     * @param idx  an index
+     * @return the value at the given index
+     * @since 1.0
      */
-    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, Comparator<? super T> comparator) {
-        List<T> answer = uniqueItems(self, comparator);
-        if (mutate) {
-            self.clear();
-            self.addAll(answer);
-        }
-        return mutate ? self : answer;
-    }
-
-    private static <T> List<T> uniqueItems(Iterable<T> self, Comparator<? super T> comparator) {
-        List<T> answer = new ArrayList<>();
-        for (T t : self) {
-            boolean duplicated = false;
-            for (T t2 : answer) {
-                if (comparator.compare(t, t2) == 0) {
-                    duplicated = true;
-                    break;
-                }
-            }
-            if (!duplicated)
-                answer.add(t);
+    public static <T> T getAt(List<T> self, int idx) {
+        int size = self.size();
+        int i = normaliseIndex(idx, size);
+        if (i < size) {
+            return self.get(i);
+        } else {
+            return null;
         }
-        return answer;
     }
 
     /**
-     * Remove all duplicates from a given List.
-     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new List is returned.
-     * The order of members in the List are compared by the given Comparator.
-     * For each duplicate, the first member which is returned
-     * by the given List's iterator is retained, but all other ones are removed.
-     * The given List's original order is preserved.
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
-     *
-     * def list = [a, b, c, d]
-     * List list2 = list.unique(false, new PersonComparator())
-     * assert( list2 != list {@code &&} list2 == [a, b, c] )
-     * </pre>
-     *
-     * @param self       a List
-     * @param mutate     false will always cause a new List to be created, true will mutate List in place
-     * @param comparator a Comparator
-     * @return self      the List without duplicates
-     * @since 2.4.0
+     * Support subscript operator for list access.
      */
-    public static <T> List<T> unique(List<T> self, boolean mutate, Comparator<? super T> comparator) {
-        return (List<T>) unique((Collection<T>) self, mutate, comparator);
+    public static <T> T getAt(List<T> self, Number idx) {
+        return getAt(self, idx.intValue());
     }
 
     /**
-     * Returns an iterator equivalent to this iterator but with all duplicated items
-     * removed where duplicate (equal) items are deduced by calling the supplied Closure condition.
-     * <p>
-     * If the supplied Closure takes a single parameter, the argument passed will be each element,
-     * and the closure should return a value used for comparison (either using
-     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
-     * If the closure takes two parameters, two items from the Iterator
-     * will be passed as arguments, and the closure should return an
-     * int value (with 0 indicating the items are not unique).
+     * Support the subscript operator for an Iterator. The iterator
+     * will be partially exhausted up until the idx entry after returning
+     * if a +ve or 0 idx is used, or fully exhausted if a -ve idx is used
+     * or no corresponding entry was found. Typical usage:
      * <pre class="groovyTestCase">
-     * def items = "Hello".toList() + [null, null] + "there".toList()
-     * def toLower = { it == null ? null : it.toLowerCase() }
-     * def noDups = items.iterator().toUnique(toLower).toList()
-     * assert noDups == ['H', 'e', 'l', 'o', null, 't', 'r']
+     * def iter = [2, "a", 5.3].iterator()
+     * assert iter[1] == "a"
+     * </pre>
+     * A more elaborate example:
+     * <pre class="groovyTestCase">
+     * def items = [2, "a", 5.3]
+     * def iter = items.iterator()
+     * assert iter[-1] == 5.3
+     * // iter exhausted, so reset
+     * iter = items.iterator()
+     * assert iter[1] == "a"
+     * // iter partially exhausted so now idx starts after "a"
+     * assert iter[0] == 5.3
      * </pre>
-     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].toUnique { it % 2 }</pre>
-     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].toUnique { a, b {@code ->} a {@code <=>} b }</pre>
      *
      * @param self an Iterator
-     * @param condition a Closure used to determine unique items
-     * @return an Iterator with no duplicate items
-     * @since 2.4.0
+     * @param idx  an index value (-self.size() &lt;= idx &lt; self.size())
+     * @return the value at the given index (after normalisation) or null if no corresponding value was found
+     * @since 1.7.2
      */
-    public static <T> Iterator<T> toUnique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
-        return toUnique(self, condition.getMaximumNumberOfParameters() == 1
-                ? new OrderBy<>(condition, true)
-                : new ClosureComparator<>(condition));
-    }
-
-    private static final class ToUniqueIterator<E> implements Iterator<E> {
-        private final Iterator<E> delegate;
-        private final Set<E> seen;
-        private boolean exhausted;
-        private E next;
-
-        private ToUniqueIterator(Iterator<E> delegate, Comparator<? super E> comparator) {
-            this.seen = new TreeSet<>(comparator);
-            this.delegate = delegate;
-            advance();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return !exhausted;
-        }
-
-        @Override
-        public E next() {
-            if (exhausted) throw new NoSuchElementException();
-            E result = next;
-            advance();
-            return result;
-        }
-
-        @Override
-        public void remove() {
-            if (exhausted) throw new NoSuchElementException();
-            delegate.remove();
+    public static <T> T getAt(Iterator<T> self, int idx) {
+        if (idx < 0) {
+            // calculate whole list in this case
+            // recommend avoiding -ve's as this is not as efficient
+            List<T> list = toList(self);
+            int adjustedIndex = idx + list.size();
+            if (adjustedIndex < 0 || adjustedIndex >= list.size()) return null;
+            return list.get(adjustedIndex);
         }
 
-        private void advance() {
-            boolean foundNext = false;
-            while (!foundNext && !exhausted) {
-                exhausted = !delegate.hasNext();
-                if (!exhausted) {
-                    next = delegate.next();
-                    foundNext = seen.add(next);
-                }
+        int count = 0;
+        while (self.hasNext()) {
+            if (count == idx) {
+                return self.next();
+            } else {
+                count++;
+                self.next();
             }
         }
+
+        return null;
     }
 
     /**
-     * Returns an iterator equivalent to this iterator with all duplicated
-     * items removed by using the supplied comparator.
+     * Support the subscript operator for an Iterable. Typical usage:
+     * <pre class="groovyTestCase">
+     * // custom Iterable example:
+     * class MyIterable implements Iterable {
+     *   Iterator iterator() { [1, 2, 3].iterator() }
+     * }
+     * def myIterable = new MyIterable()
+     * assert myIterable[1] == 2
      *
-     * @param self an Iterator
-     * @param comparator a Comparator used to determine unique (equal) items
-     *        If {@code null}, the Comparable natural ordering of the elements will be used.
-     * @return an Iterator with no duplicate items
-     * @since 2.4.0
+     * // Set example:
+     * def set = [1,2,3] as LinkedHashSet
+     * assert set[1] == 2
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param idx  an index value (-self.size() &lt;= idx &lt; self.size()) but using -ve index values will be inefficient
+     * @return the value at the given index (after normalisation) or null if no corresponding value was found
+     * @since 2.1.0
      */
-    public static <T> Iterator<T> toUnique(Iterator<T> self, Comparator<? super T> comparator) {
-        return new ToUniqueIterator<>(self, comparator);
+    public static <T> T getAt(Iterable<T> self, int idx) {
+        return getAt(self.iterator(), idx);
     }
 
     /**
-     * Returns an iterator equivalent to this iterator with all duplicated
-     * items removed by using the natural ordering of the items.
+     * Support the subscript operator for a Map.
+     * <pre class="groovyTestCase">def map = [1:10]
+     * assert map[1] == 10</pre>
      *
-     * @param self an Iterator
-     * @return an Iterator with no duplicate items
-     * @since 2.4.0
+     * @param self a Map
+     * @param key  an Object as a key for the map
+     * @return the value corresponding to the given key
+     * @since 1.0
      */
-    public static <T> Iterator<T> toUnique(Iterator<T> self) {
-        return toUnique(self, (Comparator<T>) null);
+    public static <K,V> V getAt(Map<K,V> self, Object key) {
+        return self.get(key);
     }
 
     /**
-     * Returns a Collection containing the items from the Iterable but with duplicates removed.
-     * The items in the Iterable are compared by the given Comparator.
-     * For each duplicate, the first member which is returned from the
-     * Iterable is retained, but all other ones are removed.
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     * Support the subscript operator for a Bitset
      *
-     * def list = [a, b, c, d]
-     * List list2 = list.toUnique(new PersonComparator())
-     * assert list2 == [a, b, c] {@code &&} list == [a, b, c, d]
-     * </pre>
+     * @param self  a BitSet
+     * @param index index to retrieve
+     * @return value of the bit at the given index
+     * @see java.util.BitSet
+     * @since 1.5.0
+     */
+    public static boolean getAt(BitSet self, int index) {
+        int i = normaliseIndex(index, self.length());
+        return self.get(i);
+    }
+
+    /**
+     * Support retrieving a subset of a BitSet using a Range
      *
-     * @param self       an Iterable
-     * @param comparator a Comparator used to determine unique (equal) items
-     *        If {@code null}, the Comparable natural ordering of the elements will be used.
-     * @return the Collection of non-duplicate items
-     * @since 2.4.0
+     * @param self  a BitSet
+     * @param range a Range defining the desired subset
+     * @return a new BitSet that represents the requested subset
+     * @see java.util.BitSet
+     * @see groovy.lang.IntRange
+     * @since 1.5.0
      */
-    public static <T> Collection<T> toUnique(Iterable<T> self, Comparator<? super T> comparator) {
-        Collection<T> result = createSimilarCollection(self);
-        addAll(result, toUnique(self.iterator(), comparator));
+    public static BitSet getAt(BitSet self, IntRange range) {
+        RangeInfo info = subListBorders(self.length(), range);
+        BitSet result = new BitSet();
+
+        int numberOfBits = info.to - info.from;
+        int adjuster = 1;
+        int offset = info.from;
+
+        if (info.reverse) {
+            adjuster = -1;
+            offset = info.to - 1;
+        }
+
+        for (int i = 0; i < numberOfBits; i++) {
+            result.set(i, self.get(offset + (adjuster * i)));
+        }
+
         return result;
     }
 
     /**
-     * Returns a List containing the items from the List but with duplicates removed.
-     * The items in the List are compared by the given Comparator.
-     * For each duplicate, the first member which is returned from the
-     * List is retained, but all other ones are removed.
-     * <p>
+     * Support the subscript operator for Collection.
      * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * class PersonComparator implements Comparator {
-     *     int compare(Object o1, Object o2) {
-     *         Person p1 = (Person) o1
-     *         Person p2 = (Person) o2
-     *         if (p1.lname != p2.lname)
-     *             return p1.lname.compareTo(p2.lname)
-     *         else
-     *             return p1.fname.compareTo(p2.fname)
-     *     }
-     *
-     *     boolean equals(Object obj) {
-     *         return this.equals(obj)
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
-     *
-     * def list = [a, b, c, d]
-     * List list2 = list.toUnique(new PersonComparator())
-     * assert list2 == [a, b, c] {@code &&} list == [a, b, c, d]
+     * assert [String, Long, Integer] == ["a",5L,2]["class"]
      * </pre>
      *
-     * @param self       a List
-     * @param comparator a Comparator used to determine unique (equal) items
-     *        If {@code null}, the Comparable natural ordering of the elements will be used.
-     * @return the List of non-duplicate items
-     * @since 2.4.0
+     * @param coll     a Collection
+     * @param property a String
+     * @return a List
+     * @since 1.0
      */
-    public static <T> List<T> toUnique(List<T> self, Comparator<? super T> comparator) {
-        return (List<T>) toUnique((Iterable<T>) self, comparator);
+    public static List getAt(Collection coll, String property) {
+        List<Object> answer = new ArrayList<>(coll.size());
+        return getAtIterable(coll, property, answer);
+    }
+
+    private static List getAtIterable(Iterable coll, String property, List<Object> answer) {
+        for (Object item : coll) {
+            if (item == null) continue;
+            Object value;
+            try {
+                value = InvokerHelper.getProperty(item, property);
+            } catch (MissingPropertyExceptionNoStack mpe) {
+                String causeString = new MissingPropertyException(mpe.getProperty(), mpe.getType()).toString();
+                throw new MissingPropertyException("Exception evaluating property '" + property +
+                        "' for " + coll.getClass().getName() + ", Reason: " + causeString);
+            }
+            answer.add(value);
+        }
+        return answer;
     }
 
+    //--------------------------------------------------------------------------
+    // getGroovydoc
+
     /**
-     * Returns a Collection containing the items from the Iterable but with duplicates removed
-     * using the natural ordering of the items to determine uniqueness.
-     * <p>
-     * <pre class="groovyTestCase">
-     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
-     * String[] expected = ['c', 'a', 't', 's', 'h']
-     * assert letters.toUnique() == expected
-     * </pre>
+     * Gets runtime groovydoc.
      *
-     * @param self       an Iterable
-     * @return the Collection of non-duplicate items
-     * @since 2.4.0
+     * @since 3.0.0
      */
-    public static <T> Collection<T> toUnique(Iterable<T> self) {
-        return toUnique(self, (Comparator<T>) null);
+    public static groovy.lang.groovydoc.Groovydoc getGroovydoc(AnnotatedElement holder) {
+        var groovydocAnnotation = holder.getAnnotation(groovy.lang.Groovydoc.class);
+        return groovydocAnnotation == null ? EMPTY_GROOVYDOC :
+            new groovy.lang.groovydoc.Groovydoc(groovydocAnnotation.value(), holder);
     }
 
+    //--------------------------------------------------------------------------
+    // getIndices
+
     /**
-     * Returns a List containing the items from the List but with duplicates removed
-     * using the natural ordering of the items to determine uniqueness.
+     * Returns indices of the collection.
      * <p>
+     * Example:
      * <pre class="groovyTestCase">
-     * def letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
-     * def expected = ['c', 'a', 't', 's', 'h']
-     * assert letters.toUnique() == expected
+     * assert 0..2 == [5, 6, 7].indices
      * </pre>
      *
-     * @param self       a List
-     * @return the List of non-duplicate items
+     * @param self a collection
+     * @return an index range
      * @since 2.4.0
      */
-    public static <T> List<T> toUnique(List<T> self) {
-        return toUnique(self, (Comparator<T>) null);
+    public static IntRange getIndices(Collection self) {
+        return new IntRange(false, 0, self.size());
     }
 
+    //--------------------------------------------------------------------------
+    // getLocation
+
     /**
-     * Returns a Collection containing the items from the Iterable but with duplicates removed.
-     * The items in the Iterable are compared by the given Closure condition.
-     * For each duplicate, the first member which is returned from the
-     * Iterable is retained, but all other ones are removed.
-     * <p>
-     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
-     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
-     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
-     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
-     *
-     * def list = [a, b, c, d]
-     * def list2 = list.toUnique{ p1, p2 {@code ->} p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
-     * assert( list2 == [a, b, c] {@code &&} list == [a, b, c, d] )
-     * def list3 = list.toUnique{ it.toString() }
-     * assert( list3 == [a, b, c] {@code &&} list == [a, b, c, d] )
-     * </pre>
+     * Gets the url of the jar file/source file containing the specified class.
      *
-     * @param self      an Iterable
-     * @param condition a Closure used to determine unique items
-     * @return a new Collection
-     * @see #toUnique(Iterable, Comparator)
-     * @since 2.4.0
+     * @param self the class
+     * @return the url of the jar, {@code null} if the specified class is from JDK
+     * @since 2.5.0
      */
-    public static <T> Collection<T> toUnique(Iterable<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
-        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
-                ? new OrderBy<>(condition, true)
-                : new ClosureComparator<>(condition);
-        return toUnique(self, comparator);
+    public static URL getLocation(Class self) {
+        CodeSource codeSource = self.getProtectionDomain().getCodeSource();
+        return (codeSource != null ? codeSource.getLocation() : null);
     }
 
+    //--------------------------------------------------------------------------
+    // getMetaClass
+
     /**
-     * Returns a List containing the items from the List but with duplicates removed.
-     * The items in the List are compared by the given Closure condition.
-     * For each duplicate, the first member which is returned from the
-     * Iterable is retained, but all other ones are removed.
-     * <p>
-     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
-     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
-     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
-     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Person {
-     *     def fname, lname
-     *     String toString() {
-     *         return fname + " " + lname
-     *     }
-     * }
-     *
-     * Person a = new Person(fname:"John", lname:"Taylor")
-     * Person b = new Person(fname:"Clark", lname:"Taylor")
-     * Person c = new Person(fname:"Tom", lname:"Cruz")
-     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     * Adds a "metaClass" property to all class objects so you can use the syntax
+     * <code>String.metaClass.myMethod = { println "foo" }</code>
      *
-     * def list = [a, b, c, d]
-     * def list2 = list.toUnique{ p1, p2 {@code ->} p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
-     * assert( list2 == [a, b, c] {@code &&} list == [a, b, c, d] )
-     * def list3 = list.toUnique{ it.toString() }
-     * assert( list3 == [a, b, c] {@code &&} list == [a, b, c, d] )
-     * </pre>
+     * @param c The java.lang.Class instance
+     * @return An MetaClass instance
+     * @since 1.5.0
+     */
+    public static MetaClass getMetaClass(Class c) {
+        MetaClassRegistry metaClassRegistry = GroovySystem.getMetaClassRegistry();
+        MetaClass mc = metaClassRegistry.getMetaClass(c);
+        if (mc instanceof ExpandoMetaClass
+                || mc instanceof DelegatingMetaClass && ((DelegatingMetaClass) mc).getAdaptee() instanceof ExpandoMetaClass)
+            return mc;
+        else {
+            return new HandleMetaClass(mc);
+        }
+    }
+
+    /**
+     * Obtains a MetaClass for an object either from the registry or in the case of
+     * a GroovyObject from the object itself.
      *
-     * @param self      a List
-     * @param condition a Closure used to determine unique items
-     * @return a new List
-     * @see #toUnique(Iterable, Comparator)
-     * @since 2.4.0
+     * @param obj The object in question
+     * @return The MetaClass
+     * @since 1.5.0
      */
-    public static <T> List<T> toUnique(List<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
-        return (List<T>) toUnique((Iterable<T>) self, condition);
+    public static MetaClass getMetaClass(Object obj) {
+        MetaClass mc = InvokerHelper.getMetaClass(obj);
+        return new HandleMetaClass(mc, obj);
     }
 
     /**
-     * Allows a Map to be iterated through in reverse order using a closure.
+     * Obtains a MetaClass for an object either from the registry or in the case of
+     * a GroovyObject from the object itself.
      *
-     * In general, the order in which the map contents are processed
-     * cannot be guaranteed. In practise, specialized forms of Map,
-     * e.g. a TreeMap will have its contents processed according to the
-     * reverse of the natural ordering of the map.
+     * @param obj The object in question
+     * @return The MetaClass
+     * @since 1.6.0
+     */
+    public static MetaClass getMetaClass(GroovyObject obj) {
+        // we need this method as trick to guarantee correct method selection
+        return getMetaClass((Object)obj);
+    }
+
+    //--------------------------------------------------------------------------
+    // getMetaProperties
+
+    /**
+     * Retrieves the list of {@link groovy.lang.MetaProperty} objects for 'self' and wraps it
+     * in a list of {@link groovy.lang.PropertyValue} objects that additionally provide
+     * the value for each property of 'self'.
      *
-     * @param self    the map over which we iterate
-     * @param closure the 1 or 2 arg closure applied on each entry of the map
-     * @return returns the self parameter
-     * @see #each(Map, Closure)
-     * @since 1.7.2
+     * @param self the receiver object
+     * @return list of {@link groovy.lang.PropertyValue} objects
+     * @see groovy.util.Expando#getMetaPropertyValues()
+     * @since 1.0
      */
-    @SuppressWarnings("unchecked")
-    public static <K, V> Map<K, V> reverseEach(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<?> closure) {
-        final Iterator<Map.Entry<K, V>> entries = reverse(self.entrySet().iterator());
-        while (entries.hasNext()) {
-            callClosureForMapEntry(closure, entries.next());
+    public static List<PropertyValue> getMetaPropertyValues(Object self) {
+        MetaClass metaClass = InvokerHelper.getMetaClass(self);
+        List<MetaProperty> mps = metaClass.getProperties();
+        List<PropertyValue> props = new ArrayList<>(mps.size());
+        for (MetaProperty mp : mps) {
+            props.add(new PropertyValue(self, mp));
         }
-        return self;
+        return props;
     }
 
+    //--------------------------------------------------------------------------
+    // getProperties
+
     /**
-     * Iterate over each element of the list in the reverse order.
-     * <pre class="groovyTestCase">def result = []
-     * [1,2,3].reverseEach { result &lt;&lt; it }
-     * assert result == [3,2,1]</pre>
+     * Convenience method that calls {@link #getMetaPropertyValues(java.lang.Object)}(self)
+     * and provides the data in form of simple key/value pairs, i.e. without
+     * type() information.
      *
-     * @param self    a List
-     * @param closure a closure to which each item is passed.
-     * @return the original list
-     * @since 1.5.0
+     * @param self the receiver object
+     * @return meta properties as Map of key/value pairs
+     * @since 1.0
      */
-    public static <T> List<T> reverseEach(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        each(new ReverseListIterator<>(self), closure);
-        return self;
+    public static Map<String, Object> getProperties(Object self) {
+        List<PropertyValue> metaProps = getMetaPropertyValues(self);
+        Map<String, Object> props = new LinkedHashMap<>(metaProps.size());
+
+        for (PropertyValue mp : metaProps) {
+            try {
+                props.put(mp.getName(), mp.getValue());
+            } catch (Exception e) {
+                java.util.logging.Logger.getLogger(DefaultGroovyMethods.class.getName())
+                    .throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
+            }
+        }
+        return props;
     }
 
+    //--------------------------------------------------------------------------
+    // getRootLoader
+
     /**
-     * Iterate over each element of the set in reverse order.
-     * <pre class="groovyTestCase">
-     * TreeSet navSet = [2, 4, 1, 3]  // natural order is sorted
-     * List result = []
-     * navSet.reverseEach { result &lt;&lt; it }
-     * assert result == [4, 3, 2, 1]
-     * </pre>
+     * Iterates through the classloader parents until it finds a loader with a class
+     * named "org.codehaus.groovy.tools.RootLoader". If there is no such class
+     * <code>null</code> will be returned. The name is used for comparison because
+     * a direct comparison using == may fail as the class may be loaded through
+     * different classloaders.
      *
-     * @param self    a NavigableSet
-     * @param closure a closure to which each item is passed.
-     * @return the original NavigableSet
-     * @since 4.0.11
+     * @param self a ClassLoader
+     * @return the rootLoader for the ClassLoader
+     * @see org.codehaus.groovy.tools.RootLoader
+     * @since 1.5.0
      */
-    public static <T> NavigableSet<T> reverseEach(NavigableSet<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        each(self.descendingIterator(), closure);
-        return self;
+    public static ClassLoader getRootLoader(ClassLoader self) {
+        while (true) {
+            if (self == null) return null;
+            if (isRootLoaderClassOrSubClass(self)) return self;
+            self = self.getParent();
+        }
+    }
+
+    private static boolean isRootLoaderClassOrSubClass(ClassLoader self) {
+        Class current = self.getClass();
+        while(!current.getName().equals(Object.class.getName())) {
+            if(current.getName().equals(RootLoader.class.getName())) return true;
+            current = current.getSuperclass();
+        }
+
+        return false;
     }
 
+    //--------------------------------------------------------------------------
+    // grep
+
     /**
      * Iterates over the collection of items which this Object represents and returns each item that matches
      * the given filter - calling the <code>{@link #isCase(java.lang.Object, java.lang.Object)}</code>
@@ -6605,8123 +6426,8419 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         return grep(self, Closure.IDENTITY);
     }
 
+    //--------------------------------------------------------------------------
+    // groupBy
+
     /**
-     * Convert an iterator to a List. The iterator will become
-     * exhausted of elements after making this conversion.
+     * Sorts all Iterable members into groups determined by the supplied mapping closure.
+     * The closure should return the key that this item should be grouped by. The returned
+     * LinkedHashMap will have an entry for each distinct key returned from the closure,
+     * with each value being a list of items for that group.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [0:[2,4,6], 1:[1,3,5]] == [1,2,3,4,5,6].groupBy { it % 2 }
+     * </pre>
      *
-     * @param self an iterator
-     * @return a List
-     * @since 1.5.0
+     * @param self    a collection to group
+     * @param closure a closure mapping entries on keys
+     * @return a new Map grouped by keys
+     * @since 2.2.0
      */
-    public static <T> List<T> toList(Iterator<T> self) {
-
-        List<T> answer = new ArrayList<>();
-        while (self.hasNext()) {
-            answer.add(self.next());
+    public static <K, T> Map<K, List<T>> groupBy(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<K> closure) {
+        Map<K, List<T>> answer = new LinkedHashMap<>();
+        for (T element : self) {
+            K value = closure.call(element);
+            groupAnswer(answer, element, value);
         }
         return answer;
     }
 
     /**
-     * Convert an Iterable to a List. The Iterable's iterator will
-     * become exhausted of elements after making this conversion.
-     * <p>
+     * Sorts all Iterable members into (sub)groups determined by the supplied
+     * mapping closures. Each closure should return the key that this item
+     * should be grouped by. The returned LinkedHashMap will have an entry for each
+     * distinct 'key path' returned from the closures, with each value being a list
+     * of items for that 'group path'.
+     *
      * Example usage:
-     * <pre class="groovyTestCase">def x = [1,2,3] as HashSet
-     * assert x.class == HashSet
-     * assert x.toList() instanceof List</pre>
+     * <pre class="groovyTestCase">def result = [1,2,3,4,5,6].groupBy({ it % 2 }, { it {@code <} 4 })
+     * assert result == [1:[(true):[1, 3], (false):[5]], 0:[(true):[2], (false):[4, 6]]]</pre>
      *
-     * @param self an Iterable
-     * @return a List
-     * @since 1.8.7
-     */
-    public static <T> List<T> toList(Iterable<T> self) {
-        return toList(self.iterator());
-    }
-
-    /**
-     * Convert an enumeration to a List.
+     * Another example:
+     * <pre>def sql = groovy.sql.Sql.newInstance(/&ast; ... &ast;/)
+     * def data = sql.rows("SELECT * FROM a_table").groupBy({ it.column1 }, { it.column2 }, { it.column3 })
+     * if (data.val1.val2.val3) {
+     *     // there exists a record where:
+     *     //   a_table.column1 == val1
+     *     //   a_table.column2 == val2, and
+     *     //   a_table.column3 == val3
+     * } else {
+     *     // there is no such record
+     * }</pre>
+     * If an empty array of closures is supplied the IDENTITY Closure will be used.
      *
-     * @param self an enumeration
-     * @return a List
-     * @since 1.5.0
+     * @param self     a collection to group
+     * @param closures an array of closures, each mapping entries on keys
+     * @return a new Map grouped by keys on each criterion
+     * @since 2.2.0
+     * @see Closure#IDENTITY
      */
-    public static <T> List<T> toList(Enumeration<T> self) {
-        List<T> answer = new ArrayList<>();
-        while (self.hasMoreElements()) {
-            answer.add(self.nextElement());
+    public static Map groupBy(Iterable self, Object... closures) {
+        final Closure head = closures.length == 0 ? Closure.IDENTITY : (Closure) closures[0];
+
+        @SuppressWarnings("unchecked")
+        Map<Object, List> first = groupBy(self, head);
+        if (closures.length < 2)
+            return first;
+
+        final Object[] tail = new Object[closures.length - 1];
+        System.arraycopy(closures, 1, tail, 0, closures.length - 1); // Arrays.copyOfRange only since JDK 1.6
+
+        // inject([:]) { a,e {@code ->} a {@code <<} [(e.key): e.value.groupBy(tail)] }
+        Map<Object, Map> acc = new LinkedHashMap<>();
+        for (Map.Entry<Object, List> item : first.entrySet()) {
+            acc.put(item.getKey(), groupBy(item.getValue(), tail));
         }
-        return answer;
+
+        return acc;
     }
 
     /**
-     * A variant of withCollectedValues for Iterators.
+     * Sorts all Iterable members into (sub)groups determined by the supplied
+     * mapping closures. Each closure should return the key that this item
+     * should be grouped by. The returned LinkedHashMap will have an entry for each
+     * distinct 'key path' returned from the closures, with each value being a list
+     * of items for that 'group path'.
      *
-     * @param keys           an Iterator
-     * @param collector      the Map into which the transformed entries are put
-     * @param valueTransform a function for transforming Iterator elements into values
-     * @return the collector with all transformed values added to it
-     * @see #withCollectedValues(Iterable, Map, Function)
-     * @since 5.0.0
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * def result = [1,2,3,4,5,6].groupBy([{ it % 2 }, { it {@code <} 4 }])
+     * assert result == [1:[(true):[1, 3], (false):[5]], 0:[(true):[2], (false):[4, 6]]]
+     * </pre>
+     *
+     * Another example:
+     * <pre>
+     * def sql = groovy.sql.Sql.newInstance(/&ast; ... &ast;/)
+     * def data = sql.rows("SELECT * FROM a_table").groupBy([{ it.column1 }, { it.column2 }, { it.column3 }])
+     * if (data.val1.val2.val3) {
+     *     // there exists a record where:
+     *     //   a_table.column1 == val1
+     *     //   a_table.column2 == val2, and
+     *     //   a_table.column3 == val3
+     * } else {
+     *     // there is no such record
+     * }
+     * </pre>
+     * If an empty list of closures is supplied the IDENTITY Closure will be used.
+     *
+     * @param self     a collection to group
+     * @param closures a list of closures, each mapping entries on keys
+     * @return a new Map grouped by keys on each criterion
+     * @since 2.2.0
+     * @see Closure#IDENTITY
      */
-    public static <K, V> Map<K, V> withCollectedValues(Iterator<K> keys, Map<K, V> collector, Function<? super K, V> valueTransform) {
-        return collectEntries(keys, collector, Function.identity(), valueTransform);
+    public static Map groupBy(Iterable self, List<Closure> closures) {
+        return groupBy(self, closures.toArray());
     }
 
     /**
-     * A variant of withCollectedValues for Iterators.
+     * Groups the members of a map into sub maps determined by the
+     * supplied mapping closure. The closure will be passed a Map.Entry or
+     * key and value (depending on the number of parameters the closure accepts)
+     * and should return the key that each item should be grouped under.  The
+     * resulting map will have an entry for each 'group' key returned by the
+     * closure, with values being the map members from the original map that
+     * belong to each group. (If instead of a map, you want a list of map entries
+     * use {code}groupEntriesBy{code}.)
+     * <p>
+     * If the <code>self</code> map is one of TreeMap, Hashtable or Properties,
+     * the returned Map will preserve that type, otherwise a LinkedHashMap will
+     * be returned.
+     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy { it.value % 2 }
+     * assert result == [0:[b:2, d:4, f:6], 1:[a:1, c:3, e:5]]</pre>
      *
-     * @param keys           an Iterator
-     * @param valueTransform a function for transforming Iterator elements into values
-     * @return a Map of the transformed entries
-     * @see #withCollectedValues(Iterable, Function)
-     * @since 5.0.0
+     * @param self    a map to group
+     * @param closure a closure mapping entries on keys
+     * @return a new Map grouped by keys
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> withCollectedValues(Iterator<K> keys, Function<? super K, V> valueTransform) {
-        return withCollectedValues(keys, new LinkedHashMap<>(), valueTransform);
+    public static <G, K, V> Map<G, Map<K, V>> groupBy(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<G> closure) {
+        final Map<G, List<Map.Entry<K, V>>> initial = groupEntriesBy(self, closure);
+        final Map<G, Map<K, V>> answer = new LinkedHashMap<>();
+        for (Map.Entry<G, List<Map.Entry<K, V>>> outer : initial.entrySet()) {
+            G key = outer.getKey();
+            List<Map.Entry<K, V>> entries = outer.getValue();
+            Map<K, V> target = createSimilarMap(self);
+            putAll(target, entries);
+            answer.put(key, target);
+        }
+        return answer;
     }
 
     /**
-     * Transform Iterable elements into Map entries with keys unchanged
-     * and values transformed using the supplied function.
-     * The supplied collector map is used as the destination for transformed entries.
-     * <pre class="groovyTestCase">
-     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
-     * assert languages.withCollectedValues([Clojure:7], String::size) ==
-     *     [Clojure:7, Groovy:6, Java:4, Kotlin:6, Scala:5]
-     * </pre>
-     * This method is a convenience method for {@link #collectEntries(Iterable, Map, Function, Function)}
-     * with the {@code keyTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
+     * Groups the members of a map into sub maps determined by the supplied
+     * mapping closures. Each closure will be passed a Map.Entry or key and
+     * value (depending on the number of parameters the closure accepts) and
+     * should return the key that each item should be grouped under. The
+     * resulting map will have an entry for each 'group path' returned by all
+     * closures, with values being the map members from the original map that
+     * belong to each such 'group path'.
      *
-     * @param keys           an Iterable
-     * @param collector      the Map into which the transformed entries are put
-     * @param valueTransform a function for transforming Iterable elements into values
-     * @return the collector with all transformed values added to it
-     * @since 5.0.0
+     * If the <code>self</code> map is one of TreeMap, Hashtable, or Properties,
+     * the returned Map will preserve that type, otherwise a LinkedHashMap will
+     * be returned.
+     *
+     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy({ it.value % 2 }, { it.key.next() })
+     * assert result == [1:[b:[a:1], d:[c:3], f:[e:5]], 0:[c:[b:2], e:[d:4], g:[f:6]]]</pre>
+     * If an empty array of closures is supplied the IDENTITY Closure will be used.
+     *
+     * @param self     a map to group
+     * @param closures an array of closures that map entries on keys
+     * @return a new map grouped by keys on each criterion
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    public static <K, V> Map<K, V> withCollectedValues(Iterable<K> keys, Map<K, V> collector, Function<? super K, V> valueTransform) {
-        return collectEntries(keys.iterator(), collector, Function.identity(), valueTransform);
+    public static Map<Object, Map> groupBy(Map self, Object... closures) {
+        @SuppressWarnings("unchecked")
+        final Closure<Object> head = closures.length == 0 ? Closure.IDENTITY : (Closure) closures[0];
+
+        @SuppressWarnings("unchecked")
+        Map<Object, Map> first = groupBy(self, head);
+        if (closures.length < 2)
+            return first;
+
+        final Object[] tail = new Object[closures.length - 1];
+        System.arraycopy(closures, 1, tail, 0, closures.length - 1); // Arrays.copyOfRange only since JDK 1.6
+
+        Map<Object, Map> acc = new LinkedHashMap<>();
+        for (Map.Entry<Object, Map> item: first.entrySet()) {
+            acc.put(item.getKey(), groupBy(item.getValue(), tail));
+        }
+
+        return acc;
     }
 
     /**
-     * Transform Iterable elements into Map entries with keys unchanged
-     * and values transformed using the supplied function.
-     * <pre class="groovyTestCase">
-     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
-     * assert languages.withCollectedValues(String::size) ==
-     *     [Groovy:6, Java:4, Kotlin:6, Scala:5]
-     * </pre>
-     * This method is a convenience method for {@link #collectEntries(Iterable, Function, Function)}
-     * with the {@code keyTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
+     * Groups the members of a map into sub maps determined by the supplied
+     * mapping closures. Each closure will be passed a Map.Entry or key and
+     * value (depending on the number of parameters the closure accepts) and
+     * should return the key that each item should be grouped under. The
+     * resulting map will have an entry for each 'group path' returned by all
+     * closures, with values being the map members from the original map that
+     * belong to each such 'group path'.
      *
-     * @param keys           an Iterable
-     * @param valueTransform a function for transforming Iterable elements into values
-     * @return a Map of the transformed entries
-     * @since 5.0.0
+     * If the <code>self</code> map is one of TreeMap, Hashtable, or Properties,
+     * the returned Map will preserve that type, otherwise a LinkedHashMap will
+     * be returned.
+     *
+     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy([{ it.value % 2 }, { it.key.next() }])
+     * assert result == [1:[b:[a:1], d:[c:3], f:[e:5]], 0:[c:[b:2], e:[d:4], g:[f:6]]]</pre>
+     * If an empty list of closures is supplied the IDENTITY Closure will be used.
+     *
+     * @param self     a map to group
+     * @param closures a list of closures that map entries on keys
+     * @return a new map grouped by keys on each criterion
+     * @since 1.8.1
+     * @see Closure#IDENTITY
      */
-    public static <K, V> Map<K, V> withCollectedValues(Iterable<K> keys, Function<? super K, V> valueTransform) {
-        return withCollectedValues(keys.iterator(), new LinkedHashMap<>(), valueTransform);
+    public static Map<Object, Map> groupBy(Map self, List<Closure> closures) {
+        return groupBy(self, closures.toArray());
     }
 
     /**
-     * A variant of withCollectedKeys for Iterators.
+     * Groups the current element according to the value
      *
-     * @param values       an Iterator
-     * @param collector    the Map into which the transformed entries are put
-     * @param keyTransform a function for transforming Iterator elements into values
-     * @return the collector with all transformed values added to it
-     * @see #withCollectedKeys(Iterable, Map, Function)
-     * @since 5.0.0
+     * @param answer  the map containing the results
+     * @param element the element to be placed
+     * @param value   the value according to which the element will be placed
+     * @since 1.5.0
      */
-    public static <K, V> Map<K, V> withCollectedKeys(Iterator<V> values, Map<K, V> collector, Function<? super V, K> keyTransform) {
-        return collectEntries(values, collector, keyTransform, Function.identity());
+    protected static <K, T> void groupAnswer(final Map<K, List<T>> answer, T element, K value) {
+        List<T> groupedElements = answer.computeIfAbsent(value, k -> new ArrayList<>());
+
+        groupedElements.add(element);
     }
 
+    //--------------------------------------------------------------------------
+    // groupEntriesBy
+
     /**
-     * A variant of withCollectedKeys for Iterators.
+     * Groups all map entries into groups determined by the
+     * supplied mapping closure. The closure will be passed a Map.Entry or
+     * key and value (depending on the number of parameters the closure accepts)
+     * and should return the key that each item should be grouped under.  The
+     * resulting map will have an entry for each 'group' key returned by the
+     * closure, with values being the list of map entries that belong to each
+     * group. (If instead of a list of map entries, you want an actual map
+     * use {code}groupBy{code}.)
+     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupEntriesBy { it.value % 2 }
+     * assert result[0]*.key == ["b", "d", "f"]
+     * assert result[1]*.value == [1, 3, 5]</pre>
      *
-     * @param values       an Iterator
-     * @param keyTransform a function for transforming Iterator elements into values
-     * @return a Map of the transformed entries
-     * @see #withCollectedKeys(Iterable, Function)
-     * @since 5.0.0
+     * @param self    a map to group
+     * @param closure a 1 or 2 arg Closure mapping entries on keys
+     * @return a new Map grouped by keys
+     * @since 1.5.2
      */
-    public static <K, V> Map<K, V> withCollectedKeys(Iterator<V> values, Function<? super V, K> keyTransform) {
-        return withCollectedKeys(values, new LinkedHashMap<>(), keyTransform);
+    public static <G, K, V> Map<G, List<Map.Entry<K, V>>> groupEntriesBy(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<G> closure) {
+        final Map<G, List<Map.Entry<K, V>>> answer = new LinkedHashMap<>();
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            G value = callClosureForMapEntry(closure, entry);
+            groupAnswer(answer, entry, value);
+        }
+        return answer;
     }
 
+    //--------------------------------------------------------------------------
+
     /**
-     * Transform Iterable elements into Map entries with values unchanged
-     * and keys transformed using the supplied function.
-     * The supplied map is used as the destination for transformed entries.
-     * <pre class="groovyTestCase">
-     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
-     * def firstLetter = s {@code ->} s[0]
-     * assert languages.withCollectedKeys([C:'Clojure'], firstLetter) ==
-     *     [C:'Clojure', G:'Groovy', J:'Java', K:'Kotlin', S:'Scala']
-     * </pre>
-     * This method is a convenience method for {@link #collectEntries(Iterable, Map, Function, Function)}
-     * with the {@code valueTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
+     * Identity check. Since == is overridden in Groovy with the meaning of equality
+     * we need some fallback to check for object identity.  Invoke using the
+     * 'is' method, like so: <code>def same = this.is(that)</code>
      *
-     * @param values       an Iterable that will become the added entry values
-     * @param collector    the Map into which the transformed entries are put
-     * @param keyTransform a function for transforming Iterator elements into keys
-     * @return the collector with all transformed values added to it
-     * @since 5.0.0
+     * @param self  an object
+     * @param other an object to compare identity with
+     * @return true if self and other are both references to the same
+     *         instance, false otherwise
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> withCollectedKeys(Iterable<V> values, Map<K, V> collector, Function<? super V, K> keyTransform) {
-        return collectEntries(values.iterator(), collector, keyTransform, Function.identity());
+    public static boolean is(Object self, Object other) {
+        return self == other;
     }
 
     /**
-     * Transform Iterable elements into Map entries with values unchanged
-     * and keys transformed using the supplied function.
-     * <pre class="groovyTestCase">
-     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
-     * def firstLetter = s {@code ->} s[0]
-     * assert languages.withCollectedKeys(firstLetter) ==
-     *     [G:'Groovy', J:'Java', K:'Kotlin', S:'Scala']
-     * </pre>
-     * This method is a convenience method for {@link #collectEntries(Iterable, Function, Function)}
-     * with the {@code valueTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
+     * Allows the closure to be called for the object reference self.
+     * Synonym for 'with()'.
      *
-     * @param values       an Iterable that will become the added entry values
-     * @param keyTransform a function for transforming Iterator elements into keys
-     * @return the collector with all transformed values added to it
-     * @since 5.0.0
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return result of calling the closure
+     * @see #with(Object, Closure)
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> withCollectedKeys(Iterable<V> values, Function<? super V, K> keyTransform) {
-        return withCollectedKeys(values.iterator(), new LinkedHashMap<>(), keyTransform);
+    public static <T,U> T identity(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+                    Closure<T> closure) {
+        return DefaultGroovyMethods.with(self, closure);
     }
 
     /**
-     * Finds the first value matching the closure condition.
-     *
+     * Allows the closure to be called for the object reference self.
+     * <p>
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For instance, the following method calls to the append()
+     * method are invoked on the StringBuilder instance:
      * <pre class="groovyTestCase">
-     * def numbers = [1, 2, 3]
-     * def result = numbers.find { it {@code >} 1}
-     * assert result == 2
+     * def b = new StringBuilder().with {
+     *   append('foo')
+     *   append('bar')
+     *   return it
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * This is commonly used to simplify object creation, such as this example:
+     * <pre>
+     * def p = new Person().with {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     *   return it
+     * }
+     * </pre>
+     * The other typical usage, uses the self object while creating some value:
+     * <pre>
+     * def fullName = person.with{ "$firstName $lastName" }
      * </pre>
      *
-     * @param self    an Object with an iterator returning its values
-     * @param closure a closure condition
-     * @return the first Object found or null if none was found
-     * @since 1.0
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return result of calling the closure
+     * @see #with(Object, boolean, Closure)
+     * @see #tap(Object, Closure)
+     * @since 1.5.0
      */
-    public static Object find(Object self, Closure closure) {
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
-        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
-            Object value = iter.next();
-            if (bcw.call(value)) {
-                return value;
-            }
-        }
-        return null;
+    @SuppressWarnings("unchecked")
+    public static <T,U> T with(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        return (T) with(self, false, (Closure<Object>)closure);
     }
 
     /**
-     * Finds the first item matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
-     * <p>
-     * Example:
+     * Allows the closure to be called for the object reference self.
+     * <p/>
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For example, the following method calls to the append()
+     * method are invoked on the StringBuilder instance and then, because
+     * 'returning' is true, the self instance is returned:
      * <pre class="groovyTestCase">
-     * def items = [null, 0, 0.0, false, '', [], 42, 43]
-     * assert items.find() == 42
+     * def b = new StringBuilder().with(true) {
+     *   append('foo')
+     *   append('bar')
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * The returning parameter is commonly set to true when using with to simplify object
+     * creation, such as this example:
+     * <pre>
+     * def p = new Person().with(true) {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     * }
      * </pre>
+     * Alternatively, 'tap' is an alias for 'with(true)', so that method can be used instead.
      *
-     * @param self    an Object with an Iterator returning its values
-     * @return the first Object found or null if none was found
-     * @since 1.8.1
-     * @see Closure#IDENTITY
-     */
-    public static Object find(Object self) {
-        return find(self, Closure.IDENTITY);
-    }
-
-    /**
-     * Finds the first value matching the closure condition.  Example:
-     * <pre class="groovyTestCase">def list = [1,2,3]
-     * assert 2 == list.find { it {@code >} 1 }
+     * The other main use case for with is when returning a value calculated using self as shown here:
+     * <pre>
+     * def fullName = person.with(false){ "$firstName $lastName" }
      * </pre>
+     * Alternatively, 'with' is an alias for 'with(false)', so the boolean parameter can be omitted instead.
      *
-     * @param self    a Collection
-     * @param closure a closure condition
-     * @return the first Object found, in the order of the collections iterator, or null if no element matches
-     * @since 1.0
+     * @param self      the object to have a closure act upon
+     * @param returning if true, return the self object; otherwise, the result of calling the closure
+     * @param closure   the closure to call on the object
+     * @return the self object or the result of calling the closure depending on 'returning'
+     * @see #with(Object, Closure)
+     * @see #tap(Object, Closure)
+     * @since 2.5.0
      */
-    public static <T> T find(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
-        for (T value : self) {
-            if (bcw.call(value)) {
-                return value;
-            }
-        }
-        return null;
+    public static <T,U extends T, V extends T> T with(
+            @DelegatesTo.Target("self") U self,
+            boolean returning,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        @SuppressWarnings("unchecked")
+        final Closure<V> clonedClosure = (Closure<V>) closure.clone();
+        clonedClosure.setResolveStrategy(Closure.DELEGATE_FIRST);
+        clonedClosure.setDelegate(self);
+        V result = clonedClosure.call(self);
+        return returning ? self : result;
     }
 
     /**
-     * Finds the first item matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * Allows the closure to be called for the object reference self (similar
+     * to <code>with</code>) and always returns self.
      * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def items = [null, 0, 0.0, false, '', [], 42, 43]
-     * assert items.find() == 42
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For instance, the following method calls to the append()
+     * method are invoked on the StringBuilder instance:
+     * <pre>
+     * def b = new StringBuilder().tap {
+     *   append('foo')
+     *   append('bar')
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * This is commonly used to simplify object creation, such as this example:
+     * <pre>
+     * def p = new Person().tap {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     * }
      * </pre>
      *
-     * @param self    a Collection
-     * @return the first Object found or null if none was found
-     * @since 1.8.1
-     * @see Closure#IDENTITY
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return self
+     * @see #with(Object, boolean, Closure)
+     * @see #with(Object, Closure)
+     * @since 2.5.0
      */
-    public static <T> T find(Collection<T> self) {
-        return find(self, Closure.IDENTITY);
+    @SuppressWarnings("unchecked")
+    public static <T,U> U tap(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        return (U) with(self, true, (Closure<Object>)closure);
     }
 
     /**
-     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result obtained from calling the closure, otherwise returns null.
-     * <p>
-     * <pre class="groovyTestCase">
-     * int[] numbers = [1, 2, 3]
-     * assert numbers.findResult { if(it {@code >} 1) return it } == 2
-     * assert numbers.findResult { if(it {@code >} 4) return it } == null
-     * </pre>
+     * Allows the subscript operator to be used to set dynamically named property values.
+     * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
+     * of groovy is neater and more concise but only works with property names which
+     * are known at compile time.
      *
-     * @param self      an Object with an iterator returning its values
-     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result of the closure
-     * @since 1.7.5
+     * @param self     the object to act upon
+     * @param property the name of the property to set
+     * @param newValue the value to set
+     * @since 1.0
      */
-    public static Object findResult(Object self, Closure condition) {
-        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); ) {
-            Object value = iter.next();
-            Object result = condition.call(value);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
+    public static void putAt(Object self, String property, Object newValue) {
+        InvokerHelper.setProperty(self, property, newValue);
     }
 
     /**
-     * Treats the object as iterable, iterating through the values it represents and returns the first non-null value, otherwise returns null.
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Foo {
-     *     List items
-     *     Iterator iterator() {
-     *         items.iterator()
-     *     }
-     * }
-     * assert new Foo(items: [null, 2, 4]).findResult() == 2
-     * assert new Foo(items: [null, null]).findResult() == null
-     * </pre>
+     * Scoped use method
      *
-     * @param self      an Object with an iterator returning its values
-     * @return the first non-null result of the closure
-     * @since 4.0.9
+     * @param self          any Object
+     * @param categoryClass a category class to use
+     * @param closure       the closure to invoke with the category in place
+     * @return the value returned from the closure
+     * @since 1.0
      */
-    public static Object findResult(Object self) {
-        return findResult(self, Closure.IDENTITY);
+    public static <T> T use(Object self, Class categoryClass, Closure<T> closure) {
+        return GroovyCategorySupport.use(categoryClass, closure);
     }
 
     /**
-     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result obtained from calling the closure, otherwise returns the defaultResult.
-     * <p>
-     * <pre class="groovyTestCase">
-     * int[] numbers = [1, 2, 3]
-     * assert numbers.findResult(5) { if(it {@code >} 1) return it } == 2
-     * assert numbers.findResult(5) { if(it {@code >} 4) return it } == 5
-     * </pre>
+     * Extend object with category methods.
+     * All methods for given class and all super classes will be added to the object.
      *
-     * @param self          an Object with an iterator returning its values
-     * @param defaultResult an Object that should be returned if all closure results are null
-     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result of the closure, otherwise the default value
-     * @since 1.7.5
+     * @param self          any Class
+     * @param categoryClasses a category classes to use
+     * @since 1.6.0
      */
-    public static Object findResult(Object self, Object defaultResult, Closure condition) {
-        Object result = findResult(self, condition);
-        if (result == null) return defaultResult;
-        return result;
+    public static void mixin(MetaClass self, List<Class> categoryClasses) {
+        MixinInMetaClass.mixinClassesToMetaClass(self, categoryClasses);
     }
 
     /**
-     * Treats the object as iterable, iterating through the values it represents and returns the first non-null result, otherwise returns the defaultResult.
-     * <p>
-     * <pre class="groovyTestCase">
-     * class Foo {
-     *     List items
-     *     Iterator iterator() {
-     *         items.iterator()
-     *     }
-     * }
-     * assert new Foo(items: [null, 2, 4]).findResult(5) == 2
-     * assert new Foo(items: [null, null]).findResult(5) == 5
-     * </pre>
+     * Extend class globally with category methods.
+     * All methods for given class and all super classes will be added to the class.
      *
-     * @param self          an Object with an iterator returning its values
-     * @param defaultResult an Object that should be returned if all elements are null
-     * @return the first non-null element, otherwise the default value
-     * @since 4.0.9
+     * @param self          any Class
+     * @param categoryClasses a category classes to use
+     * @since 1.6.0
      */
-    public static Object findResult(Object self, Object defaultResult) {
-        Object result = findResult(self, Closure.IDENTITY);
-        if (result == null) return defaultResult;
-        return result;
+    public static void mixin(Class self, List<Class> categoryClasses) {
+        mixin(getMetaClass(self), categoryClasses);
     }
 
     /**
-     * Iterates through the Iterator calling the given closure condition for each item but stopping once the first non-null
-     * result is found and returning that result. If all are null, the defaultResult is returned.
-     * <p>
-     * Examples:
-     * <pre class="groovyTestCase">
-     * def iter = [1,2,3].iterator()
-     * assert "Found 2" == iter.findResult("default") { it {@code >} 1 ? "Found $it" : null }
-     * assert "default" == iter.findResult("default") { it {@code >} 3 ? "Found $it" : null }
-     * </pre>
+     * Extend class globally with category methods.
      *
-     * @param self          an Iterator
-     * @param defaultResult an Object that should be returned if all closure results are null
-     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result from calling the closure, or the defaultValue
-     * @since 2.5.0
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
      */
-    public static <S, T, U extends T, V extends T> T findResult(Iterator<S> self, U defaultResult, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> condition) {
-        T result = findResult(self, condition);
-        if (result == null) return defaultResult;
-        return result;
+    public static void mixin(Class self, Class categoryClass) {
+        mixin(getMetaClass(self), Collections.singletonList(categoryClass));
     }
 
     /**
-     * Iterates through the Iterator stopping once the first non-null
-     * result is found and returning that result. If all are null, the defaultResult is returned.
-     * <p>
-     * Examples:
-     * <pre class="groovyTestCase">
-     * assert [null, 1, 2].iterator().findResult('default') == 1
-     * assert [null, null].findResult('default') == 'default'
-     * </pre>
+     * Extend class globally with category methods.
      *
-     * @param self          an Iterator
-     * @param defaultResult an Object that should be returned if all elements are null
-     * @return the first non-null result from the iterator, or the defaultValue
-     * @since 4.0.9
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
      */
-    public static <T, U extends T, V extends T> T findResult(Iterator<U> self, V defaultResult) {
-        T result = (T) findResult(self, Closure.IDENTITY);
-        return result == null ? defaultResult : result;
+    public static void mixin(Class self, Class[] categoryClass) {
+        mixin(getMetaClass(self), Arrays.asList(categoryClass));
     }
 
     /**
-     * Iterates through the Iterator calling the given closure condition for each item but stopping once the first non-null
-     * result is found and returning that result. If all results are null, null is returned.
+     * Extend class globally with category methods.
      *
-     * @param self      an Iterator
-     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result from calling the closure, or null
-     * @since 2.5.0
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
      */
-    public static <T, U> T findResult(Iterator<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> condition) {
-        while (self.hasNext()) {
-            U next = self.next();
-            T result = condition.call(next);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
+    public static void mixin(MetaClass self, Class categoryClass) {
+        mixin(self, Collections.singletonList(categoryClass));
     }
 
     /**
-     * Iterates through the Iterator stopping once the first non-null
-     * result is found and returning that result. If all results are null, null is returned.
+     * Extend class globally with category methods.
      *
-     * @param self      an Iterator
-     * @return the first non-null result from the iterator, or null
-     * @since 4.0.9
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
      */
-    public static <T> T findResult(Iterator<T> self) {
-        return (T) findResult(self, Closure.IDENTITY);
+    public static void mixin(MetaClass self, Class[] categoryClass) {
+        mixin(self, Arrays.asList(categoryClass));
     }
 
     /**
-     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
-     * result is found and returning that result. If all are null, the defaultResult is returned.
-     * <p>
-     * Examples:
-     * <pre class="groovyTestCase">
-     * def list = [1,2,3]
-     * assert "Found 2" == list.findResult("default") { it {@code >} 1 ? "Found $it" : null }
-     * assert "default" == list.findResult("default") { it {@code >} 3 ? "Found $it" : null }
-     * </pre>
+     * Scoped use method with list of categories.
      *
-     * @param self          an Iterable
-     * @param defaultResult an Object that should be returned if all closure results are null
-     * @param condition     a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result from calling the closure, or the defaultValue
-     * @since 2.5.0
+     * @param self              any Object
+     * @param categoryClassList a list of category classes
+     * @param closure           the closure to invoke with the categories in place
+     * @return the value returned from the closure
+     * @since 1.0
      */
-    public static <S, T, U extends T, V extends T> T findResult(Iterable<S> self, U defaultResult, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> condition) {
-        T result = findResult(self, condition);
-        if (result == null) return defaultResult;
-        return result;
+    public static <T> T use(Object self, List<Class> categoryClassList, Closure<T> closure) {
+        return GroovyCategorySupport.use(categoryClassList, closure);
     }
 
     /**
-     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
-     * result is found and returning that result. If all are null, the defaultResult is returned.
-     * <p>
-     * Examples:
-     * <pre class="groovyTestCase">
-     * assert [null, 1, 2].findResult('default') == 1
-     * assert [null, null].findResult('default') == 'default'
-     * </pre>
+     * Allows you to use a list of categories, specifying the list as varargs.
+     * <code>use(CategoryClass1, CategoryClass2) { ... }</code>
+     * This method saves having to wrap the category
+     * classes in a list.
      *
-     * @param self          an Iterable
-     * @param defaultResult an Object that should be returned if all elements in the iterable are null
-     * @return the first non-null element from the iterable, or the defaultValue
-     * @since 4.0.9
+     * @param self  any Object
+     * @param array a list of category classes and a Closure
+     * @return the value returned from the closure
+     * @since 1.0
      */
-    public static <T, U extends T, V extends T> T findResult(Iterable<U> self, V defaultResult) {
-        T result = (T) findResult(self, Closure.IDENTITY);
-        if (result == null) return defaultResult;
-        return result;
+    @SuppressWarnings("unchecked")
+    public static Object use(Object self, Object[] array) {
+        if (array.length < 2)
+            throw new IllegalArgumentException(
+                    "Expecting at least 2 arguments, a category class and a Closure");
+        Closure closure;
+        try {
+            closure = (Closure) array[array.length - 1];
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException("Expecting a Closure to be the last argument");
+        }
+        List<Class> list = new ArrayList<>(array.length - 1);
+        for (int i = 0; i < array.length - 1; ++i) {
+            Class categoryClass;
+            try {
+                categoryClass = (Class) array[i];
+            } catch (ClassCastException e) {
+                throw new IllegalArgumentException("Expecting a Category Class for argument " + i);
+            }
+            list.add(categoryClass);
+        }
+        return GroovyCategorySupport.use(list, closure);
     }
 
     /**
-     * Iterates through the Iterable calling the given closure condition for each item but stopping once the first non-null
-     * result is found and returning that result. If all results are null, null is returned.
+     * Inspects returns the String that matches what would be typed into a
+     * terminal to create this object.
      *
-     * @param self      an Iterable
-     * @param condition a closure that returns a non-null value to indicate that processing should stop and the value should be returned
-     * @return the first non-null result from calling the closure, or null
-     * @since 2.5.0
+     * @param self any Object
+     * @return a String that matches what would be typed into a terminal to
+     *         create this object. e.g. [1, 'hello'].inspect() {@code ->} [1, 'hello']
+     * @since 1.0
      */
-    public static <T, U> T findResult(Iterable<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> condition) {
-        return findResult(self.iterator(), condition);
+    public static String inspect(Object self) {
+        return FormatHelper.inspect(self);
     }
 
     /**
-     * Iterates through the Iterable stopping once the first non-null
-     * result is found and returning that result. If all results are null, null is returned.
+     * Provide a dynamic method invocation method which can be overloaded in
+     * classes to implement dynamic proxies easily.
      *
-     * @param self      an Iterable
-     * @return the first non-null element from the iterable, or null
-     * @since 4.0.9
+     * @param object    any Object
+     * @param method    the name of the method to call
+     * @param arguments the arguments to use
+     * @return the result of the method call
+     * @since 1.0
      */
-    public static <T> T findResult(Iterable<T> self) {
-        return (T) findResult(self.iterator(), Closure.IDENTITY);
+    public static Object invokeMethod(Object object, String method, Object arguments) {
+        return InvokerHelper.invokeMethod(object, method, arguments);
     }
 
+    //--------------------------------------------------------------------------
+    // print/println/printf/sprintf
+
     /**
-     * Returns the first non-null closure result found by passing each map entry to the closure, otherwise null is returned.
-     * If the closure takes two parameters, the entry key and value are passed.
-     * If the closure takes one parameter, the Map.Entry object is passed.
-     * <pre class="groovyTestCase">
-     * assert "Found b:3" == [a:1, b:3].findResult { if (it.value == 3) return "Found ${it.key}:${it.value}" }
-     * assert null == [a:1, b:3].findResult { if (it.value == 9) return "Found ${it.key}:${it.value}" }
-     * assert "Found a:1" == [a:1, b:3].findResult { k, v {@code ->} if (k.size() + v == 2) return "Found $k:$v" }
-     * </pre>
+     * Print a value formatted Groovy style to self if it
+     * is a Writer, otherwise to the standard output stream.
      *
-     * @param self      a Map
-     * @param condition a 1 or 2 arg Closure that returns a non-null value when processing should stop and a value should be returned
-     * @return the first non-null result collected by calling the closure, or null if no such result was found
-     * @since 1.7.5
+     * @param self  any Object
+     * @param value the value to print
+     * @since 1.0
      */
-    public static <T, K, V> T findResult(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> condition) {
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            T result = callClosureForMapEntry(condition, entry);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
+    public static void print(Object self, Object value) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            try {
+                ((Writer) self).write(FormatHelper.toString(value));
+            } catch (IOException e) {
+                // TODO: Should we have some unified function like PrintWriter.checkError()?
+            }
+        } else {
+            System.out.print(FormatHelper.toString(value));
+        }
+    }
+
     /**
-     * Returns the first non-null closure result found by passing each map entry to the closure, otherwise the defaultResult is returned.
-     * If the closure takes two parameters, the entry key and value are passed.
-     * If the closure takes one parameter, the Map.Entry object is passed.
-     * <pre class="groovyTestCase">
-     * assert "Found b:3" == [a:1, b:3].findResult("default") { if (it.value == 3) return "Found ${it.key}:${it.value}" }
-     * assert "default" == [a:1, b:3].findResult("default") { if (it.value == 9) return "Found ${it.key}:${it.value}" }
-     * assert "Found a:1" == [a:1, b:3].findResult("default") { k, v {@code ->} if (k.size() + v == 2) return "Found $k:$v" }
-     * </pre>
+     * Print a value formatted Groovy style to the print writer.
      *
-     * @param self          a Map
-     * @param defaultResult an Object that should be returned if all closure results are null
-     * @param condition     a 1 or 2 arg Closure that returns a non-null value when processing should stop and a value should be returned
-     * @return the first non-null result collected by calling the closure, or the defaultResult if no such result was found
-     * @since 1.7.5
+     * @param self  a PrintWriter
+     * @param value the value to print
+     * @since 1.0
      */
-    public static <T, U extends T, V extends T, A, B> T findResult(Map<A, B> self, U defaultResult, @ClosureParams(MapEntryOrKeyValue.class) Closure<V> condition) {
-        T result = findResult(self, condition);
-        if (result == null) return defaultResult;
-        return result;
+    public static void print(PrintWriter self, Object value) {
+        self.print(FormatHelper.toString(value));
     }
 
     /**
-     * Iterates through the Iterable transforming items using the supplied closure
-     * and collecting any non-null results.
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def list = [1,2,3]
-     * def result = list.findResults { it {@code >} 1 ? "Found $it" : null }
-     * assert result == ["Found 2", "Found 3"]
-     * </pre>
+     * Print a value formatted Groovy style to the print stream.
      *
-     * @param self               an Iterable
-     * @param filteringTransform a Closure that should return either a non-null transformed value or null for items which should be discarded
-     * @return the list of non-null transformed values
-     * @since 2.2.0
+     * @param self  a PrintStream
+     * @param value the value to print
+     * @since 1.6.0
      */
-    public static <T, U> Collection<T> findResults(Iterable<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> filteringTransform) {
-        return findResults(self.iterator(), filteringTransform);
+    public static void print(PrintStream self, Object value) {
+        self.print(FormatHelper.toString(value));
     }
 
     /**
-     * Iterates through the Iterable collecting any non-null results.
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * assert [1, null, 2, null, 3].findResults() == [1, 2, 3]
-     * </pre>
+     * Print a value to the standard output stream.
+     * This method delegates to the owner to execute the method.
      *
-     * @param self an Iterable
-     * @return the list of non-null values
-     * @since 4.0.9
+     * @param self  a generated closure
+     * @param value the value to print
+     * @since 1.0
      */
-    public static <T> Collection<T> findResults(Iterable<T> self) {
-        return findResults(self.iterator(), Closure.IDENTITY);
+    public static void print(Closure self, Object value) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "print", new Object[]{value});
     }
 
     /**
-     * Iterates through the Iterator transforming items using the supplied closure
-     * and collecting any non-null results.
+     * Print to a console in interactive format.
      *
-     * @param self               an Iterator
-     * @param filteringTransform a Closure that should return either a non-null transformed value or null for items which should be discarded
-     * @return the list of non-null transformed values
-     * @since 2.5.0
+     * @param self any Object
+     * @param out  the PrintWriter used for printing
+     * @since 1.0
      */
-    public static <T, U> Collection<T> findResults(Iterator<U> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<T> filteringTransform) {
-        List<T> result = new ArrayList<>();
-        while (self.hasNext()) {
-            U value = self.next();
-            T transformed = filteringTransform.call(value);
-            if (transformed != null) {
-                result.add(transformed);
-            }
+    public static void print(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
         }
-        return result;
+        out.print(FormatHelper.toString(self));
     }
 
     /**
-     * Iterates through the Iterator collecting any non-null results.
+     * Print a linebreak to the standard output stream.
      *
-     * @param self an Iterator
-     * @return the list of non-null values
-     * @since 4.0.9
+     * @param self any Object
+     * @since 1.0
      */
-    public static <T> Collection<T> findResults(Iterator<T> self) {
-        return findResults(self, Closure.IDENTITY);
+    public static void println(Object self) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            PrintWriter pw = new GroovyPrintWriter((Writer) self);
+            pw.println();
+        } else {
+            System.out.println();
+        }
     }
 
     /**
-     * Iterates through the map transforming items using the supplied closure
-     * and collecting any non-null results.
-     * If the closure takes two parameters, the entry key and value are passed.
-     * If the closure takes one parameter, the Map.Entry object is passed.
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def map = [a:1, b:2, hi:2, cat:3, dog:2]
-     * def result = map.findResults { k, v {@code ->} k.size() == v ? "Found $k:$v" : null }
-     * assert result == ["Found a:1", "Found hi:2", "Found cat:3"]
-     * </pre>
+     * Print a linebreak to the standard output stream.
+     * This method delegates to the owner to execute the method.
      *
-     * @param self               a Map
-     * @param filteringTransform a 1 or 2 arg Closure that should return either a non-null transformed value or null for items which should be discarded
-     * @return the list of non-null transformed values
-     * @since 1.8.1
+     * @param self  a closure
+     * @since 1.0
      */
-    public static <T, K, V> Collection<T> findResults(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> filteringTransform) {
-        List<T> result = new ArrayList<>();
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            T transformed = callClosureForMapEntry(filteringTransform, entry);
-            if (transformed != null) {
-                result.add(transformed);
-            }
-        }
-        return result;
+    public static void println(Closure self) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "println", InvokerHelper.EMPTY_ARGS);
     }
 
     /**
-     * Finds the first entry matching the closure condition.
-     * If the closure takes two parameters, the entry key and value are passed.
-     * If the closure takes one parameter, the Map.Entry object is passed.
-     * <pre class="groovyTestCase">assert [a:1, b:3].find { it.value == 3 }.key == "b"</pre>
+     * Print a value formatted Groovy style (followed by a newline) to self
+     * if it is a Writer, otherwise to the standard output stream.
      *
-     * @param self    a Map
-     * @param closure a 1 or 2 arg Closure condition
-     * @return the first Object found
+     * @param self  any Object
+     * @param value the value to print
      * @since 1.0
      */
-    public static <K, V> Map.Entry<K, V> find(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<?> closure) {
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            if (bcw.callForMap(entry)) {
-                return entry;
-            }
+    public static void println(Object self, Object value) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            final PrintWriter pw = new GroovyPrintWriter((Writer) self);
+            pw.println(value);
+        } else {
+            System.out.println(FormatHelper.toString(value));
         }
-        return null;
     }
 
     /**
-     * Finds all entries matching the closure condition. If the
-     * closure takes one parameter then it will be passed the Map.Entry.
-     * Otherwise if the closure should take two parameters, which will be
-     * the key and the value.
-     * <p>
-     * If the <code>self</code> map is one of TreeMap, LinkedHashMap, Hashtable
-     * or Properties, the returned Map will preserve that type, otherwise a HashMap will
-     * be returned.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * def result = [a:1, b:2, c:4, d:5].findAll { it.value % 2 == 0 }
-     * assert result.every { it instanceof Map.Entry }
-     * assert result*.key == ["b", "c"]
-     * assert result*.value == [2, 4]
-     * </pre>
+     * Print a value formatted Groovy style (followed by a newline) to the print writer.
      *
-     * @param self    a Map
-     * @param closure a 1 or 2 arg Closure condition applying on the entries
-     * @return a new subMap
+     * @param self  a PrintWriter
+     * @param value the value to print
      * @since 1.0
      */
-    public static <K, V> Map<K, V> findAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure closure) {
-        Map<K, V> answer = createSimilarMap(self);
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            if (bcw.callForMap(entry)) {
-                answer.put(entry.getKey(), entry.getValue());
-            }
-        }
-        return answer;
+    public static void println(PrintWriter self, Object value) {
+        self.println(FormatHelper.toString(value));
     }
 
     /**
-     * Finds all values matching the closure condition.
-     * <pre class="groovyTestCase">assert ([2,4] as Set) == ([1,2,3,4] as Set).findAll { it % 2 == 0 }</pre>
+     * Print a value formatted Groovy style (followed by a newline) to the print stream.
      *
-     * @param self    a Set
-     * @param closure a closure condition
-     * @return a Set of matching values
-     * @since 2.4.0
+     * @param self  any Object
+     * @param value the value to print
+     * @since 1.6.0
      */
-    public static <T> Set<T> findAll(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return (Set<T>) findAll((Collection<T>) self, closure);
+    public static void println(PrintStream self, Object value) {
+        self.println(FormatHelper.toString(value));
     }
 
     /**
-     * Finds all values matching the closure condition.
-     * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
+     * Print a value (followed by a newline) to the standard output stream.
+     * This method delegates to the owner to execute the method.
      *
-     * @param self    a List
-     * @param closure a closure condition
-     * @return a List of matching values
-     * @since 2.4.0
+     * @param self  a closure
+     * @param value the value to print
+     * @since 1.0
      */
-    public static <T> List<T> findAll(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return (List<T>) findAll((Collection<T>) self, closure);
+    public static void println(Closure self, Object value) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "println", new Object[]{value});
     }
 
     /**
-     * Finds all values matching the closure condition.
-     * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
+     * Print to a console in interactive format.
      *
-     * @param self    a Collection
-     * @param closure a closure condition
-     * @return a Collection of matching values
-     * @since 1.5.6
+     * @param self any Object
+     * @param out  the PrintWriter used for printing
+     * @since 1.0
      */
-    public static <T> Collection<T> findAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return findMany(createSimilarCollection(self), self.iterator(), closure);
+    public static void println(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
+        }
+        out.println(FormatHelper.toString(self));
     }
 
     /**
-     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null] as Set
-     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]] as Set
-     * </pre>
-     *
-     * @param self a Set
-     * @return a Set of the truthy values
-     * @since 2.4.0
-     * @see Closure#IDENTITY
-     */
-    public static <T> Set<T> findAll(Set<T> self) {
-        return findAll(self, Closure.IDENTITY);
-    }
-
-    /**
-     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
-     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
-     * </pre>
+     * Printf to the standard output stream.
      *
-     * @param self a List
-     * @return a List of the truthy values
-     * @since 2.4.0
-     * @see Closure#IDENTITY
+     * @param self   any Object
+     * @param format a format string
+     * @param values values referenced by the format specifiers in the format string
+     * @since 1.0
      */
-    public static <T> List<T> findAll(List<T> self) {
-        return findAll(self, Closure.IDENTITY);
+    public static void printf(Object self, String format, Object[] values) {
+        if (self instanceof PrintStream)
+            ((PrintStream)self).printf(format, values);
+        else
+            System.out.printf(format, values);
     }
 
     /**
-     * Finds the items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
-     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
-     * </pre>
+     * Printf 0 or more values to the standard output stream using a format string.
+     * This method delegates to the owner to execute the method.
      *
-     * @param self a Collection
-     * @return a Collection of the truthy values
-     * @since 1.8.1
-     * @see Closure#IDENTITY
+     * @param self   a generated closure
+     * @param format a format string
+     * @param values values referenced by the format specifiers in the format string
+     * @since 3.0.0
      */
-    public static <T> Collection<T> findAll(Collection<T> self) {
-        return findAll(self, Closure.IDENTITY);
+    public static void printf(Closure self, String format, Object[] values) {
+        Object owner = getClosureOwner(self);
+        Object[] newValues = new Object[values.length + 1];
+        newValues[0] = format;
+        System.arraycopy(values, 0, newValues, 1, values.length);
+        InvokerHelper.invokeMethod(owner, "printf", newValues);
     }
 
     /**
-     * Finds all items matching the closure condition.
+     * Printf a value to the standard output stream using a format string.
+     * This method delegates to the owner to execute the method.
      *
-     * @param self    an Object with an Iterator returning its values
-     * @param closure a closure condition
-     * @return a List of the values found
-     * @since 1.6.0
+     * @param self   a generated closure
+     * @param format a format string
+     * @param value  value referenced by the format specifier in the format string
+     * @since 3.0.0
      */
-    @SuppressWarnings("unchecked")
-    public static List findAll(Object self, Closure closure) {
-        return findMany(new ArrayList(), InvokerHelper.asIterator(self), closure);
+    public static void printf(Closure self, String format, Object value) {
+        Object owner = getClosureOwner(self);
+        Object[] newValues = new Object[2];
+        newValues[0] = format;
+        newValues[1] = value;
+        InvokerHelper.invokeMethod(owner, "printf", newValues);
     }
 
     /**
-     * Finds all items matching the IDENTITY Closure (i.e.&#160;matching Groovy truth).
+     * Prints a formatted string using the specified format string and arguments.
      * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
-     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
+     * Examples:
+     * <pre>
+     *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
+     *     printf ( "Hello, %s!\n" , [ "Groovy" ])
+     *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
+     *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
+     *
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
+     *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
+     *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
      * </pre>
      *
-     * @param self an Object with an Iterator returning its values
-     * @return a List of the truthy values
-     * @since 1.8.1
-     * @see Closure#IDENTITY
+     * @param self   any Object
+     * @param format A format string
+     * @param arg    Argument which is referenced by the format specifiers in the format
+     *               string.  The type of <code>arg</code> should be one of Object[], List,
+     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
+     * @since 1.0
      */
-    public static List findAll(Object self) {
-        return findAll(self, Closure.IDENTITY);
+    public static void printf(Object self, String format, Object arg) {
+        if (self instanceof PrintStream)
+            printf((PrintStream) self, format, arg);
+        else if (self instanceof Writer)
+            printf((Writer) self, format, arg);
+        else
+            printf(System.out, format, arg);
     }
 
-    static <T, C extends Collection<T>> C findMany(C collector, Iterator<? extends T> iter, Closure<?> closure) {
-        BooleanClosureWrapper test = new BooleanClosureWrapper(closure);
-        while (iter.hasNext()) {
-            T value = iter.next();
-            if (test.call(value)) {
-                collector.add(value);
-            }
-        }
-        return collector;
+    private static void printf(PrintStream self, String format, Object arg) {
+        self.print(sprintf(self, format, arg));
     }
 
-    /**
-     * Modifies this collection by removing its elements that are contained
-     * within the specified object array.
-     *
-     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
-     * containing items which don't match some criteria while leaving the original collection unchanged.
-     *
-     * @param  self  a Collection to be modified
-     * @param  items array containing elements to be removed from this collection
-     * @return <tt>true</tt> if this collection changed as a result of the call
-     * @see    Collection#removeAll(Collection)
-     * @since 1.7.2
-     */
-    @SuppressWarnings("unchecked")
-    public static boolean removeAll(Collection self, Object[] items) {
-        Collection pickFrom = new TreeSet(new NumberAwareComparator());
-        pickFrom.addAll(Arrays.asList(items));
-        return self.removeAll(pickFrom);
+    private static void printf(Writer self, String format, Object arg) {
+        try {
+            self.write(sprintf(self, format, arg));
+        } catch (IOException e) {
+            printf(System.out, format, arg);
+        }
     }
 
     /**
-     * Modifies this collection so that it retains only its elements that are contained
-     * in the specified array.  In other words, removes from this collection all of
-     * its elements that are not contained in the specified array.
-     *
-     * See also <code>grep</code> and <code>findAll</code> when wanting to produce a new list
-     * containing items which match some specified items but leaving the original collection unchanged.
+     * Sprintf to a string.
      *
-     * @param  self  a Collection to be modified
-     * @param  items array containing elements to be retained from this collection
-     * @return <tt>true</tt> if this collection changed as a result of the call
-     * @see    Collection#retainAll(Collection)
-     * @since 1.7.2
+     * @param self   any Object
+     * @param format a format string
+     * @param values values referenced by the format specifiers in the format string
+     * @return the resulting formatted string
+     * @since 1.5.0
      */
-    @SuppressWarnings("unchecked")
-    public static boolean retainAll(Collection self, Object[] items) {
-        Collection pickFrom = new TreeSet(new NumberAwareComparator());
-        pickFrom.addAll(Arrays.asList(items));
-        return self.retainAll(pickFrom);
+    public static String sprintf(Object self, String format, Object[] values) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        PrintStream out = new PrintStream(outputStream);
+        out.printf(format, values);
+        return outputStream.toString();
     }
 
     /**
-     * Modifies this collection so that it retains only its elements
-     * that are matched according to the specified closure condition.  In other words,
-     * removes from this collection all of its elements that don't match.
-     *
-     * <pre class="groovyTestCase">def list = ['a', 'b']
-     * list.retainAll { it == 'b' }
-     * assert list == ['b']</pre>
-     *
-     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
-     * containing items which match some criteria but leaving the original collection unchanged.
+     * Returns a formatted string using the specified format string and
+     * arguments.
      *
-     * @param  self      a Collection to be modified
-     * @param  condition a closure condition
-     * @return <tt>true</tt> if this collection changed as a result of the call
-     * @see    Iterator#remove()
-     * @since 1.7.2
+     * @param self   any Object
+     * @param format A format string
+     * @param arg    Argument which is referenced by the format specifiers in the format
+     *               string.  The type of <code>arg</code> should be one of Object[], List,
+     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
+     * @return the resulting printf'd string
+     * @since 1.5.0
      */
-    public static <T> boolean retainAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
-        Iterator iter = InvokerHelper.asIterator(self);
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
-        boolean result = false;
-        while (iter.hasNext()) {
-            Object value = iter.next();
-            if (!bcw.call(value)) {
-                iter.remove();
-                result = true;
-            }
+    public static String sprintf(Object self, String format, Object arg) {
+        if (arg instanceof Object[]) {
+            return sprintf(self, format, (Object[]) arg);
         }
-        return result;
-    }
-
-    /**
-     * Modifies this map so that it retains only its elements that are matched
-     * according to the specified closure condition.  In other words, removes from
-     * this map all of its elements that don't match. If the closure takes one
-     * parameter then it will be passed the <code>Map.Entry</code>. Otherwise the closure should
-     * take two parameters, which will be the key and the value.
-     *
-     * <pre class="groovyTestCase">def map = [a:1, b:2]
-     * map.retainAll { k,v {@code ->} k == 'b' }
-     * assert map == [b:2]</pre>
-     *
-     * See also <code>findAll</code> when wanting to produce a new map containing items
-     * which match some criteria but leaving the original map unchanged.
-     *
-     * @param self a Map to be modified
-     * @param condition a 1 or 2 arg Closure condition applying on the entries
-     * @return <tt>true</tt> if this map changed as a result of the call
-     * @since 2.5.0
-     */
-    public static <K, V> boolean retainAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure condition) {
-        Iterator<Map.Entry<K, V>> iter = self.entrySet().iterator();
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
-        boolean result = false;
-        while (iter.hasNext()) {
-            Map.Entry<K, V> entry = iter.next();
-            if (!bcw.callForMap(entry)) {
-                iter.remove();
-                result = true;
-            }
+        if (arg instanceof List) {
+            return sprintf(self, format, ((List) arg).toArray());
+        }
+        if (!arg.getClass().isArray()) {
+            Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
+            o[0] = arg;
+            return sprintf(self, format, o);
         }
-        return result;
-    }
-
-    /**
-     * Modifies this collection by removing the elements that are matched according
-     * to the specified closure condition.
-     *
-     * <pre class="groovyTestCase">def list = ['a', 'b']
-     * list.removeAll { it == 'b' }
-     * assert list == ['a']</pre>
-     *
-     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
-     * containing items which match some criteria but leaving the original collection unchanged.
-     *
-     * @param  self a Collection to be modified
-     * @param  condition a closure condition
-     * @return <tt>true</tt> if this collection changed as a result of the call
-     * @see    Iterator#remove()
-     * @since 1.7.2
-     */
-    public static <T> boolean removeAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
-        return self.removeIf(new BooleanClosurePredicate<>(condition));
-    }
-
-    /**
-     * Modifies this map by removing the elements that are matched according to the
-     * specified closure condition. If the closure takes one parameter then it will be
-     * passed the <code>Map.Entry</code>. Otherwise the closure should take two parameters, which
-     * will be the key and the value.
-     *
-     * <pre class="groovyTestCase">def map = [a:1, b:2]
-     * map.removeAll { k,v {@code ->} k == 'b' }
-     * assert map == [a:1]</pre>
-     *
-     * See also <code>findAll</code> when wanting to produce a new map containing items
-     * which match some criteria but leaving the original map unchanged.
-     *
-     * @param self a Map to be modified
-     * @param condition a 1 or 2 arg Closure condition applying on the entries
-     * @return <tt>true</tt> if this map changed as a result of the call
-     * @since 2.5.0
-     */
-    public static <K, V> boolean removeAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure condition) {
-        return self.entrySet().removeIf(new BooleanClosureForMapPredicate<>(condition));
-    }
-
-    /**
-     * Splits all items into two lists based on the closure condition.
-     * The first list contains all items matching the closure expression.
-     * The second list all those that don't.
-     *
-     * @param self    an Object with an Iterator returning its values
-     * @param closure a closure condition
-     * @return a List whose first item is the accepted values and whose second item is the rejected values
-     * @since 1.6.0
-     */
-    @SuppressWarnings("unchecked")
-    public static Collection split(Object self, Closure closure) {
-        List accept = new ArrayList();
-        List reject = new ArrayList();
-        return split(closure, accept, reject, InvokerHelper.asIterator(self));
-    }
-
-    /**
-     * Splits all items into two collections based on the closure condition.
-     * The first list contains all items which match the closure expression.
-     * The second list all those that don't.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">assert [[2,4],[1,3]] == [1,2,3,4].split { it % 2 == 0 }</pre>
-     *
-     * @param self    a Collection of values
-     * @param closure a closure condition
-     * @return a List whose first item is the accepted values and whose second item is the rejected values
-     * @since 1.6.0
-     */
-    public static <T> Collection<Collection<T>> split(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        Collection<T> accept = createSimilarCollection(self);
-        Collection<T> reject = createSimilarCollection(self);
-        Iterator<T> iter = self.iterator();
-        return split(closure, accept, reject, iter);
-    }
 
-    static <T> Collection<Collection<T>> split(Closure closure, Collection<T> accept, Collection<T> reject, Iterator<T> iter) {
-        List<Collection<T>> answer = new ArrayList<>();
-        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
-        while (iter.hasNext()) {
-            T value = iter.next();
-            if (bcw.call(value)) {
-                accept.add(value);
-            } else {
-                reject.add(value);
+        Object[] ans;
+        String elemType = arg.getClass().getName();
+        switch (elemType) {
+            case "[I":
+                int[] ia = (int[]) arg;
+                ans = new Integer[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    ans[i] = ia[i];
+                }
+                break;
+            case "[C":
+                char[] ca = (char[]) arg;
+                ans = new Character[ca.length];
+                for (int i = 0; i < ca.length; i++) {
+                    ans[i] = ca[i];
+                }
+                break;
+            case "[Z": {
+                boolean[] ba = (boolean[]) arg;
+                ans = new Boolean[ba.length];
+                for (int i = 0; i < ba.length; i++) {
+                    ans[i] = ba[i];
+                }
+                break;
+            }
+            case "[B": {
+                byte[] ba = (byte[]) arg;
+                ans = new Byte[ba.length];
+                for (int i = 0; i < ba.length; i++) {
+                    ans[i] = ba[i];
+                }
+                break;
             }
+            case "[S":
+                short[] sa = (short[]) arg;
+                ans = new Short[sa.length];
+                for (int i = 0; i < sa.length; i++) {
+                    ans[i] = sa[i];
+                }
+                break;
+            case "[F":
+                float[] fa = (float[]) arg;
+                ans = new Float[fa.length];
+                for (int i = 0; i < fa.length; i++) {
+                    ans[i] = fa[i];
+                }
+                break;
+            case "[J":
+                long[] la = (long[]) arg;
+                ans = new Long[la.length];
+                for (int i = 0; i < la.length; i++) {
+                    ans[i] = la[i];
+                }
+                break;
+            case "[D":
+                double[] da = (double[]) arg;
+                ans = new Double[da.length];
+                for (int i = 0; i < da.length; i++) {
+                    ans[i] = da[i];
+                }
+                break;
+            default:
+                throw new RuntimeException("sprintf(String," + arg + ")");
         }
-        answer.add(accept);
-        answer.add(reject);
-        return answer;
-    }
-
-    /**
-     * Splits all items into two collections based on the closure condition.
-     * The first list contains all items which match the closure expression.
-     * The second list all those that don't.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">assert [[2,4],[1,3]] == [1,2,3,4].split { it % 2 == 0 }</pre>
-     *
-     * @param self    a List of values
-     * @param closure a closure condition
-     * @return a List whose first item is the accepted values and whose second item is the rejected values
-     * @since 2.4.0
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> List<List<T>> split(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return (List<List<T>>) (List<?>) split((Collection<T>) self, closure);
+        return sprintf(self, format, ans);
     }
 
-    /**
-     * Splits all items into two collections based on the closure condition.
-     * The first list contains all items which match the closure expression.
-     * The second list all those that don't.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">assert [[2,4] as Set, [1,3] as Set] == ([1,2,3,4] as Set).split { it % 2 == 0 }</pre>
-     *
-     * @param self    a Set of values
-     * @param closure a closure condition
-     * @return a List whose first item is the accepted values and whose second item is the rejected values
-     * @since 2.4.0
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> List<Set<T>> split(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return (List<Set<T>>) (List<?>) split((Collection<T>) self, closure);
+    private static Object getClosureOwner(Closure<?> cls) {
+        Object owner =  cls.getOwner();
+        while (owner instanceof GeneratedClosure) {
+            owner = ((Closure<?>) owner).getOwner();
+        }
+        return owner;
     }
 
-    /**
-     * Finds all non-null subsequences of a list.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">def result = [1, 2, 3].subsequences()
-     * assert result == [[1, 2, 3], [1, 3], [2, 3], [1, 2], [1], [2], [3]] as Set</pre>
-     *
-     * @param self the List of items
-     * @return the subsequences from the list
-     * @since 1.7.0
-     */
-    public static <T> Set<List<T>> subsequences(List<T> self) {
-        return GroovyCollections.subsequences(self);
-    }
+    //-------------------------------------------------------------------------
+    // isCase/isNotCase
 
     /**
-     * Finds all permutations of an iterable.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">def result = [1, 2, 3].permutations()
-     * assert result == [[3, 2, 1], [3, 1, 2], [1, 3, 2], [2, 3, 1], [2, 1, 3], [1, 2, 3]] as Set</pre>
+     * Method for overloading the behavior of the 'case' method in switch statements.
+     * The default implementation handles arrays types but otherwise simply delegates
+     * to Object#equals, but this may be overridden for other types. In this example:
+     * <pre> switch( a ) {
+     *   case b: //some code
+     * }</pre>
+     * "some code" is called when <code>b.isCase( a )</code> returns
+     * <code>true</code>.
      *
-     * @param self the Iterable of items
-     * @return the permutations from the list
-     * @since 1.7.0
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the switchValue is deemed to be equal to the caseValue
+     * @since 1.0
      */
-    public static <T> Set<List<T>> permutations(Iterable<T> self) {
-        Set<List<T>> ans = new HashSet<>();
-        PermutationGenerator<T> generator = new PermutationGenerator<>(self);
-        while (generator.hasNext()) {
-            ans.add(generator.next());
+    public static boolean isCase(Object caseValue, Object switchValue) {
+        if (caseValue.getClass().isArray()) {
+            return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
         }
-        return ans;
+        return caseValue.equals(switchValue);
     }
 
     /**
-     * Finds all permutations of an iterable, applies a function to each permutation and collects the result
-     * into a list.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">Set result = [1, 2, 3].permutations { it.collect { v {@code ->} 2*v }}
-     * assert result == [[6, 4, 2], [6, 2, 4], [2, 6, 4], [4, 6, 2], [4, 2, 6], [2, 4, 6]] as Set</pre>
+     * Special 'Case' implementation for Class, which allows testing
+     * whether some switch value is assignable from the given case class.
      *
-     * @param self the Iterable of items
-     * @param function the function to apply on each permutation
-     * @return the list of results of the application of the function on each permutation
-     * @since 2.2.0
-     */
-    public static <T,V> List<V> permutations(Iterable<T> self, Closure<V> function) {
-        return collect(permutations(self), function);
-    }
-
-    /**
-     * Adds GroovyCollections#transpose(List) as a method on lists.
-     * A Transpose Function takes a collection of columns and returns a collection of
-     * rows. The first row consists of the first element from each column. Successive
-     * rows are constructed similarly.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * def result = [['a', 'b'], [1, 2]].transpose()
-     * assert result == [['a', 1], ['b', 2]]
-     * </pre>
+     * If the switch value is an object, {@code isCase} will return true if the
+     * switch value is assignment compatible with the class (case value),
+     * i.e.&nbsp;is an {@code instanceof} the class, for example:
      * <pre class="groovyTestCase">
-     * def result = [['a', 'b'], [1, 2], [3, 4]].transpose()
-     * assert result == [['a', 1, 3], ['b', 2, 4]]
+     * def someList = []
+     * switch (someList) {
+     *   case List:
+     *     assert true : 'is a list'
+     *     break
+     *   case Map:
+     *     assert false : 'is not a Map'
+     *     break
+     *   default:
+     *     assert false : 'should never get here'
+     *     break
+     * }
      * </pre>
      *
-     * @param self a List of lists
-     * @return a List of the transposed lists
-     * @see groovy.util.GroovyCollections#transpose(java.util.List)
-     * @since 1.5.0
-     */
-    public static List transpose(List self) {
-        return GroovyCollections.transpose(self);
-    }
-
-    /**
-     * Sorts all Iterable members into groups determined by the supplied mapping closure.
-     * The closure should return the key that this item should be grouped by. The returned
-     * LinkedHashMap will have an entry for each distinct key returned from the closure,
-     * with each value being a list of items for that group.
-     * <p>
-     * Example usage:
+     * If the switch value is a class, {@code isCase} will return true if the
+     * switch value is assignable from the given class (case value), i.e.&nbsp;the case class
+     * is the same as, or a superclass, or a super-interface of the switch class, for example:
      * <pre class="groovyTestCase">
-     * assert [0:[2,4,6], 1:[1,3,5]] == [1,2,3,4,5,6].groupBy { it % 2 }
+     * switch (ArrayList) {
+     *   case List:
+     *     assert true : 'is a list'
+     *     break
+     *   case Map:
+     *     assert false : 'is not a Map'
+     *     break
+     *   default:
+     *     assert false : 'should never get here'
+     *     break
+     * }
      * </pre>
      *
-     * @param self    a collection to group
-     * @param closure a closure mapping entries on keys
-     * @return a new Map grouped by keys
-     * @since 2.2.0
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the switchValue is deemed to be assignable from the given class
+     * @since 1.0
      */
-    public static <K, T> Map<K, List<T>> groupBy(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<K> closure) {
-        Map<K, List<T>> answer = new LinkedHashMap<>();
-        for (T element : self) {
-            K value = closure.call(element);
-            groupAnswer(answer, element, value);
+    @SuppressWarnings("unchecked")
+    public static boolean isCase(Class caseValue, Object switchValue) {
+        if (switchValue instanceof Class) {
+            Class val = (Class) switchValue;
+            return caseValue.isAssignableFrom(val);
         }
-        return answer;
+        return caseValue.isInstance(switchValue);
     }
 
     /**
-     * Sorts all Iterable members into (sub)groups determined by the supplied
-     * mapping closures. Each closure should return the key that this item
-     * should be grouped by. The returned LinkedHashMap will have an entry for each
-     * distinct 'key path' returned from the closures, with each value being a list
-     * of items for that 'group path'.
-     *
-     * Example usage:
-     * <pre class="groovyTestCase">def result = [1,2,3,4,5,6].groupBy({ it % 2 }, { it {@code <} 4 })
-     * assert result == [1:[(true):[1, 3], (false):[5]], 0:[(true):[2], (false):[4, 6]]]</pre>
-     *
-     * Another example:
-     * <pre>def sql = groovy.sql.Sql.newInstance(/&ast; ... &ast;/)
-     * def data = sql.rows("SELECT * FROM a_table").groupBy({ it.column1 }, { it.column2 }, { it.column3 })
-     * if (data.val1.val2.val3) {
-     *     // there exists a record where:
-     *     //   a_table.column1 == val1
-     *     //   a_table.column2 == val2, and
-     *     //   a_table.column3 == val3
-     * } else {
-     *     // there is no such record
+     * 'Case' implementation for collections which tests if the 'switch'
+     * operand is contained in any of the 'case' values.
+     * For example:
+     * <pre class="groovyTestCase">switch( 3 ) {
+     *   case [1,3,5]:
+     *     assert true
+     *     break
+     *   default:
+     *     assert false
      * }</pre>
-     * If an empty array of closures is supplied the IDENTITY Closure will be used.
      *
-     * @param self     a collection to group
-     * @param closures an array of closures, each mapping entries on keys
-     * @return a new Map grouped by keys on each criterion
-     * @since 2.2.0
-     * @see Closure#IDENTITY
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the caseValue is deemed to contain the switchValue
+     * @see java.util.Collection#contains(java.lang.Object)
+     * @since 1.0
      */
-    public static Map groupBy(Iterable self, Object... closures) {
-        final Closure head = closures.length == 0 ? Closure.IDENTITY : (Closure) closures[0];
-
-        @SuppressWarnings("unchecked")
-        Map<Object, List> first = groupBy(self, head);
-        if (closures.length < 2)
-            return first;
-
-        final Object[] tail = new Object[closures.length - 1];
-        System.arraycopy(closures, 1, tail, 0, closures.length - 1); // Arrays.copyOfRange only since JDK 1.6
-
-        // inject([:]) { a,e {@code ->} a {@code <<} [(e.key): e.value.groupBy(tail)] }
-        Map<Object, Map> acc = new LinkedHashMap<>();
-        for (Map.Entry<Object, List> item : first.entrySet()) {
-            acc.put(item.getKey(), groupBy(item.getValue(), tail));
-        }
-
-        return acc;
+    public static boolean isCase(Collection caseValue, Object switchValue) {
+        return caseValue.contains(switchValue);
     }
 
     /**
-     * Sorts all Iterable members into (sub)groups determined by the supplied
-     * mapping closures. Each closure should return the key that this item
-     * should be grouped by. The returned LinkedHashMap will have an entry for each
-     * distinct 'key path' returned from the closures, with each value being a list
-     * of items for that 'group path'.
-     *
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * def result = [1,2,3,4,5,6].groupBy([{ it % 2 }, { it {@code <} 4 }])
-     * assert result == [1:[(true):[1, 3], (false):[5]], 0:[(true):[2], (false):[4, 6]]]
-     * </pre>
-     *
-     * Another example:
-     * <pre>
-     * def sql = groovy.sql.Sql.newInstance(/&ast; ... &ast;/)
-     * def data = sql.rows("SELECT * FROM a_table").groupBy([{ it.column1 }, { it.column2 }, { it.column3 }])
-     * if (data.val1.val2.val3) {
-     *     // there exists a record where:
-     *     //   a_table.column1 == val1
-     *     //   a_table.column2 == val2, and
-     *     //   a_table.column3 == val3
-     * } else {
-     *     // there is no such record
+     * 'Case' implementation for iterable types which tests if the 'switch'
+     * operand is contained in any of the 'case' values.
+     * For example:
+     * <pre class="groovyTestCase">Iterable it = {[1,3,5].iterator()}
+     * switch( 3 ) {
+     *   case it:
+     *     assert true
+     *     break
+     *   default:
+     *     assert false
      * }
+     *
+     * //GROOVY-7919
+     * assert 1 in it
+     * assert 2 !in it
      * </pre>
-     * If an empty list of closures is supplied the IDENTITY Closure will be used.
      *
-     * @param self     a collection to group
-     * @param closures a list of closures, each mapping entries on keys
-     * @return a new Map grouped by keys on each criterion
-     * @since 2.2.0
-     * @see Closure#IDENTITY
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the caseValue is deemed to contain the switchValue
+     * @see #contains(Iterable,Object)
+     * @since 5.0.0
      */
-    public static Map groupBy(Iterable self, List<Closure> closures) {
-        return groupBy(self, closures.toArray());
+    public static boolean isCase(Iterable caseValue, Object switchValue) {
+        return contains(caseValue, switchValue);
     }
 
     /**
-     * Groups all map entries into groups determined by the
-     * supplied mapping closure. The closure will be passed a Map.Entry or
-     * key and value (depending on the number of parameters the closure accepts)
-     * and should return the key that each item should be grouped under.  The
-     * resulting map will have an entry for each 'group' key returned by the
-     * closure, with values being the list of map entries that belong to each
-     * group. (If instead of a list of map entries, you want an actual map
-     * use {code}groupBy{code}.)
-     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupEntriesBy { it.value % 2 }
-     * assert result[0]*.key == ["b", "d", "f"]
-     * assert result[1]*.value == [1, 3, 5]</pre>
+     * 'Case' implementation for maps which tests the groovy truth
+     * value obtained using the 'switch' operand as key.
+     * For example:
+     * <pre class="groovyTestCase">switch( 'foo' ) {
+     *   case [foo:true, bar:false]:
+     *     assert true
+     *     break
+     *   default:
+     *     assert false
+     * }</pre>
      *
-     * @param self    a map to group
-     * @param closure a 1 or 2 arg Closure mapping entries on keys
-     * @return a new Map grouped by keys
-     * @since 1.5.2
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return the groovy truth value from caseValue corresponding to the switchValue key
+     * @since 1.7.6
      */
-    public static <G, K, V> Map<G, List<Map.Entry<K, V>>> groupEntriesBy(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<G> closure) {
-        final Map<G, List<Map.Entry<K, V>>> answer = new LinkedHashMap<>();
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            G value = callClosureForMapEntry(closure, entry);
-            groupAnswer(answer, entry, value);
-        }
-        return answer;
+    public static boolean isCase(Map caseValue, Object switchValue) {
+        return DefaultTypeTransformation.castToBoolean(caseValue.get(switchValue));
     }
 
     /**
-     * Groups the members of a map into sub maps determined by the
-     * supplied mapping closure. The closure will be passed a Map.Entry or
-     * key and value (depending on the number of parameters the closure accepts)
-     * and should return the key that each item should be grouped under.  The
-     * resulting map will have an entry for each 'group' key returned by the
-     * closure, with values being the map members from the original map that
-     * belong to each group. (If instead of a map, you want a list of map entries
-     * use {code}groupEntriesBy{code}.)
-     * <p>
-     * If the <code>self</code> map is one of TreeMap, Hashtable or Properties,
-     * the returned Map will preserve that type, otherwise a LinkedHashMap will
-     * be returned.
-     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy { it.value % 2 }
-     * assert result == [0:[b:2, d:4, f:6], 1:[a:1, c:3, e:5]]</pre>
+     * Special 'case' implementation for all numbers, which delegates to the
+     * <code>compareTo()</code> method for comparing numbers of different
+     * types.
      *
-     * @param self    a map to group
-     * @param closure a closure mapping entries on keys
-     * @return a new Map grouped by keys
-     * @since 1.0
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the numbers are deemed equal
+     * @since 1.5.0
      */
-    public static <G, K, V> Map<G, Map<K, V>> groupBy(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<G> closure) {
-        final Map<G, List<Map.Entry<K, V>>> initial = groupEntriesBy(self, closure);
-        final Map<G, Map<K, V>> answer = new LinkedHashMap<>();
-        for (Map.Entry<G, List<Map.Entry<K, V>>> outer : initial.entrySet()) {
-            G key = outer.getKey();
-            List<Map.Entry<K, V>> entries = outer.getValue();
-            Map<K, V> target = createSimilarMap(self);
-            putAll(target, entries);
-            answer.put(key, target);
-        }
-        return answer;
+    public static boolean isCase(Number caseValue, Number switchValue) {
+        return NumberMath.compareTo(caseValue, switchValue) == 0;
     }
 
     /**
-     * Groups the members of a map into sub maps determined by the supplied
-     * mapping closures. Each closure will be passed a Map.Entry or key and
-     * value (depending on the number of parameters the closure accepts) and
-     * should return the key that each item should be grouped under. The
-     * resulting map will have an entry for each 'group path' returned by all
-     * closures, with values being the map members from the original map that
-     * belong to each such 'group path'.
-     *
-     * If the <code>self</code> map is one of TreeMap, Hashtable, or Properties,
-     * the returned Map will preserve that type, otherwise a LinkedHashMap will
-     * be returned.
-     *
-     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy({ it.value % 2 }, { it.key.next() })
-     * assert result == [1:[b:[a:1], d:[c:3], f:[e:5]], 0:[c:[b:2], e:[d:4], g:[f:6]]]</pre>
-     * If an empty array of closures is supplied the IDENTITY Closure will be used.
-     *
-     * @param self     a map to group
-     * @param closures an array of closures that map entries on keys
-     * @return a new map grouped by keys on each criterion
-     * @since 1.8.1
-     * @see Closure#IDENTITY
+     * @since 4.0.0
      */
-    public static Map<Object, Map> groupBy(Map self, Object... closures) {
-        @SuppressWarnings("unchecked")
-        final Closure<Object> head = closures.length == 0 ? Closure.IDENTITY : (Closure) closures[0];
+    public static boolean isNotCase(Number caseValue, Number switchValue) {
+        return !isCase(caseValue, switchValue);
+    }
 
-        @SuppressWarnings("unchecked")
-        Map<Object, Map> first = groupBy(self, head);
-        if (closures.length < 2)
-            return first;
+    /**
+     * @since 4.0.0
+     */
+    public static boolean isNotCase(Object caseValue, Object switchValue) {
+        return !isCase(caseValue, switchValue);
+    }
 
-        final Object[] tail = new Object[closures.length - 1];
-        System.arraycopy(closures, 1, tail, 0, closures.length - 1); // Arrays.copyOfRange only since JDK 1.6
+    /**
+     * @since 4.0.0
+     */
+    public static boolean isNotCase(Class<?> caseValue, Object switchValue) {
+        return !isCase(caseValue, switchValue);
+    }
 
-        Map<Object, Map> acc = new LinkedHashMap<>();
-        for (Map.Entry<Object, Map> item: first.entrySet()) {
-            acc.put(item.getKey(), groupBy(item.getValue(), tail));
-        }
+    /**
+     * @since 4.0.0
+     */
+    public static boolean isNotCase(Closure<?> caseValue, Object switchValue) {
+        return !caseValue.isCase(switchValue);
+    }
 
-        return acc;
+    /**
+     * @since 4.0.0
+     */
+    public static boolean isNotCase(Collection<?> caseValue, Object switchValue) {
+        return !isCase(caseValue, switchValue);
     }
 
     /**
-     * Groups the members of a map into sub maps determined by the supplied
-     * mapping closures. Each closure will be passed a Map.Entry or key and
-     * value (depending on the number of parameters the closure accepts) and
-     * should return the key that each item should be grouped under. The
-     * resulting map will have an entry for each 'group path' returned by all
-     * closures, with values being the map members from the original map that
-     * belong to each such 'group path'.
-     *
-     * If the <code>self</code> map is one of TreeMap, Hashtable, or Properties,
-     * the returned Map will preserve that type, otherwise a LinkedHashMap will
-     * be returned.
-     *
-     * <pre class="groovyTestCase">def result = [a:1,b:2,c:3,d:4,e:5,f:6].groupBy([{ it.value % 2 }, { it.key.next() }])
-     * assert result == [1:[b:[a:1], d:[c:3], f:[e:5]], 0:[c:[b:2], e:[d:4], g:[f:6]]]</pre>
-     * If an empty list of closures is supplied the IDENTITY Closure will be used.
-     *
-     * @param self     a map to group
-     * @param closures a list of closures that map entries on keys
-     * @return a new map grouped by keys on each criterion
-     * @since 1.8.1
-     * @see Closure#IDENTITY
+     * @since 4.0.0
+     */
+    public static boolean isNotCase(Map<?, ?>     caseValue, Object switchValue) {
+        return !isCase(caseValue, switchValue);
+    }
+
+    //--------------------------------------------------------------------------
+
+    /**
+     * Returns an iterator equivalent to this iterator with all duplicated items removed
+     * by using Groovy's default number-aware comparator. The original iterator will become
+     * exhausted of elements after determining the unique values. A new iterator
+     * for the unique values will be returned.
+     *
+     * @param self an Iterator
+     * @return a new Iterator of the unique items from the original iterator
+     * @since 1.5.5
      */
-    public static Map<Object, Map> groupBy(Map self, List<Closure> closures) {
-        return groupBy(self, closures.toArray());
+    public static <T> Iterator<T> unique(Iterator<T> self) {
+        return uniqueItems(new IteratorIterableAdapter<>(self)).listIterator();
     }
 
     /**
-     * Groups the current element according to the value
+     * Modifies this collection to remove all duplicated items, using Groovy's
+     * default number-aware comparator.
+     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
      *
-     * @param answer  the map containing the results
-     * @param element the element to be placed
-     * @param value   the value according to which the element will be placed
-     * @since 1.5.0
+     * @param self a collection
+     * @return the now modified collection
+     * @see #unique(Collection, boolean)
+     * @since 1.0
      */
-    protected static <K, T> void groupAnswer(final Map<K, List<T>> answer, T element, K value) {
-        List<T> groupedElements = answer.computeIfAbsent(value, k -> new ArrayList<>());
-
-        groupedElements.add(element);
+    public static <T> Collection<T> unique(Collection<T> self) {
+        return unique(self, true);
     }
 
-    // internal helper method
-    protected static <T, K, V> T callClosureForMapEntry(@ClosureParams(value=FromString.class, options={"K,V","Map.Entry<K,V>"}) Closure<T> closure, Map.Entry<K,V> entry) {
-        if (closure.getMaximumNumberOfParameters() == 2) {
-            return closure.call(entry.getKey(), entry.getValue());
-        }
-        return closure.call(entry);
+    /**
+     * Modifies this List to remove all duplicated items, using Groovy's
+     * default number-aware comparator.
+     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     *
+     * @param self a List
+     * @return the now modified List
+     * @see #unique(Collection, boolean)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self) {
+        return (List<T>) unique((Collection<T>) self, true);
     }
 
-    // internal helper method
-    protected static <T> T callClosureForLine(@ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure, String line, int counter) {
-        if (closure.getMaximumNumberOfParameters() == 2) {
-            return closure.call(line, counter);
+    /**
+     * Remove all duplicates from a given Collection using Groovy's default number-aware comparator.
+     * If mutate is true, it works by modifying the original object (and also returning it).
+     * If mutate is false, a new collection is returned leaving the original unchanged.
+     * <pre class="groovyTestCase">
+     * assert [1,3] == [1,3,3].unique()
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2, 3]
+     * def uniq = orig.unique(false)
+     * assert orig == [1, 3, 2, 3]
+     * assert uniq == [1, 3, 2]
+     * </pre>
+     *
+     * @param self a collection
+     * @param mutate false will cause a new list containing unique items from the collection to be created, true will mutate collections in place
+     * @return the now modified collection
+     * @since 1.8.1
+     */
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate) {
+        List<T> answer = uniqueItems(self);
+        if (mutate) {
+            self.clear();
+            self.addAll(answer);
         }
-        return closure.call(line);
+        return mutate ? self : answer ;
     }
 
-    // internal helper method
-    protected static <T, K, V> T callClosureForMapEntryAndCounter(@ClosureParams(value=FromString.class, options={"K,V,Integer", "K,V","Map.Entry<K,V>"}) Closure<T> closure, Map.Entry<K,V> entry, int counter) {
-        if (closure.getMaximumNumberOfParameters() == 3) {
-            return closure.call(entry.getKey(), entry.getValue(), counter);
-        }
-        if (closure.getMaximumNumberOfParameters() == 2) {
-            return closure.call(entry, counter);
+    private static <T> List<T> uniqueItems(Iterable<T> self) {
+        List<T> answer = new ArrayList<>();
+        for (T t : self) {
+            boolean duplicated = false;
+            for (T t2 : answer) {
+                if (coercedEquals(t, t2)) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated)
+                answer.add(t);
         }
-        return closure.call(entry);
+        return answer;
     }
 
     /**
-     * Performs the same function as the version of inject that takes an initial value, but
-     * uses the head of the Collection as the initial value, and iterates over the tail.
+     * Remove all duplicates from a given List using Groovy's default number-aware comparator.
+     * If mutate is true, it works by modifying the original object (and also returning it).
+     * If mutate is false, a new collection is returned leaving the original unchanged.
      * <pre class="groovyTestCase">
-     * assert 1 * 2 * 3 * 4 == [ 1, 2, 3, 4 ].inject { acc, val {@code ->} acc * val }
-     * assert ['b'] == [['a','b'], ['b','c'], ['d','b']].inject { acc, val {@code ->} acc.intersect( val ) }
-     * LinkedHashSet set = [ 't', 'i', 'm' ]
-     * assert 'tim' == set.inject { a, b {@code ->} a + b }
+     * assert [1,3] == [1,3,3].unique()
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2, 3]
+     * def uniq = orig.unique(false)
+     * assert orig == [1, 3, 2, 3]
+     * assert uniq == [1, 3, 2]
      * </pre>
      *
-     * @param self         a Collection
-     * @param closure      a closure
-     * @return the result of the last closure call
-     * @throws NoSuchElementException if the collection is empty.
-     * @see #inject(Collection, Object, Closure)
-     * @since 1.8.7
+     * @param self a List
+     * @param mutate false will cause a new List containing unique items from the List to be created, true will mutate List in place
+     * @return the now modified List
+     * @since 2.4.0
      */
-    @SuppressWarnings("unchecked")
-    public static <T, V extends T> T inject(Collection<T> self, @ClosureParams(value=FromString.class,options="V,T") Closure<V> closure ) {
-        if( self.isEmpty() ) {
-            throw new NoSuchElementException( "Cannot call inject() on an empty collection without passing an initial value." ) ;
-        }
-        Iterator<T> iter = self.iterator();
-        T head = iter.next();
-        Collection<T> tail = tail(self);
-        if (!tail.iterator().hasNext()) {
-            return head;
-        }
-        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
-        return (T) inject((Collection) tail, head, closure);
+    public static <T> List<T> unique(List<T> self, boolean mutate) {
+        return (List<T>) unique((Collection<T>) self, mutate);
     }
 
     /**
-     * Iterates through the given Collection, passing in the initial value to
-     * the 2-arg closure along with the first item. The result is passed back (injected) into
-     * the closure along with the second item. The new result is injected back into
-     * the closure along with the third item and so on until the entire collection
-     * has been used. Also known as <tt>foldLeft</tt> or <tt>reduce</tt> in functional parlance.
-     *
-     * Examples:
-     * <pre class="groovyTestCase">
-     * assert 1*1*2*3*4 == [1,2,3,4].inject(1) { acc, val {@code ->} acc * val }
-     *
-     * assert 0+1+2+3+4 == [1,2,3,4].inject(0) { acc, val {@code ->} acc + val }
-     *
-     * assert 'The quick brown fox' ==
-     *     ['quick', 'brown', 'fox'].inject('The') { acc, val {@code ->} acc + ' ' + val }
-     *
-     * assert 'bat' ==
-     *     ['rat', 'bat', 'cat'].inject('zzz') { min, next {@code ->} next {@code <} min ? next : min }
-     *
-     * def max = { a, b {@code ->} [a, b].max() }
-     * def animals = ['bat', 'rat', 'cat']
-     * assert 'rat' == animals.inject('aaa', max)
-     * </pre>
-     * Visual representation of the last example above:
-     * <pre>
-     *    initVal  animals[0]
-     *       v        v
-     * max('aaa',   'bat')  {@code =>}  'bat'  animals[1]
-     *                            v       v
-     *                      max('bat',  'rat')  {@code =>}  'rat'  animals[2]
-     *                                                v       v
-     *                                          max('rat',  'cat')  {@code =>}  'rat'
-     * </pre>
+     * Provides a method that compares two comparables using Groovy's
+     * default number aware comparator.
      *
-     * @param self         a Collection
-     * @param initialValue some initial value
-     * @param closure      a closure
-     * @return the result of the last closure call
-     * @since 1.0
+     * @param self a Comparable
+     * @param other another Comparable
+     * @return a -ve number, 0 or a +ve number according to Groovy's compareTo contract
+     * @since 1.6.0
      */
-    @SuppressWarnings("unchecked")
-    public static <E, T, U extends T, V extends T> T inject(Collection<E> self, U initialValue, @ClosureParams(value=FromString.class,options="U,E") Closure<V> closure) {
-        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
-        return (T) inject((Iterator) self.iterator(), initialValue, closure);
+    public static int numberAwareCompareTo(Comparable self, Comparable other) {
+        return COMPARABLE_NUMBER_AWARE_COMPARATOR.compare(self, other);
     }
 
     /**
-     * Iterates through the given Map, passing in the initial value to
-     * the 2-arg Closure along with the first item (or 3-arg Closure along with the first key and value).
-     * The result is passed back (injected) into
-     * the closure along with the second item. The new result is injected back into
-     * the closure along with the third item and so on until the entire collection
-     * has been used. Also known as <tt>foldLeft</tt> or <tt>reduce</tt> in functional parlance.
+     * Returns an iterator equivalent to this iterator but with all duplicated items
+     * removed by using a Closure to determine duplicate (equal) items.
+     * The original iterator will be fully processed after the call.
+     * <p>
+     * If the closure takes a single parameter, the argument passed will be each element,
+     * and the closure should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the Iterator
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
      *
-     * Examples:
-     * <pre class="groovyTestCase">
-     * def map = [a:1, b:2, c:3]
-     * assert map.inject([]) { list, k, v {@code ->}
-     *   list + [k] * v
-     * } == ['a', 'b', 'b', 'c', 'c', 'c']
-     * </pre>
+     * @param self      an Iterator
+     * @param condition a Closure used to determine unique items
+     * @return the modified Iterator
+     * @since 1.5.5
+     */
+    public static <T> Iterator<T> unique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<>(condition, true)
+                : new ClosureComparator<>(condition);
+        return unique(self, comparator);
+    }
+
+    /**
+     * A convenience method for making a collection unique using a Closure
+     * to determine duplicate (equal) items.
+     * <p>
+     * If the closure takes a single parameter, the
+     * argument passed will be each element, and the closure
+     * should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b {@code ->} a {@code <=>} b }</pre>
      *
-     * @param self         a Map
-     * @param initialValue some initial value
-     * @param closure      a 2 or 3 arg Closure
-     * @return the result of the last closure call
-     * @since 1.8.1
+     * @param self    a Collection
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @see #unique(Collection, boolean, Closure)
+     * @since 1.0
      */
-    public static <K, V, T, U extends T, W extends T> T inject(Map<K, V> self, U initialValue, @ClosureParams(value=FromString.class,options={"U,Map.Entry<K,V>","U,K,V"})  Closure<W> closure) {
-        T value = initialValue;
-        for (Map.Entry<K, V> entry : self.entrySet()) {
-            if (closure.getMaximumNumberOfParameters() == 3) {
-                value = closure.call(value, entry.getKey(), entry.getValue());
-            } else {
-                value = closure.call(value, entry);
-            }
-        }
-        return value;
+    public static <T> Collection<T> unique(Collection<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return unique(self, true, closure);
     }
 
     /**
-     * Iterates through the given Iterator, passing in the initial value to
-     * the closure along with the first item. The result is passed back (injected) into
-     * the closure along with the second item. The new result is injected back into
-     * the closure along with the third item and so on until the Iterator has been
-     * expired of values. Also known as foldLeft in functional parlance.
+     * A convenience method for making a List unique using a Closure
+     * to determine duplicate (equal) items.
+     * <p>
+     * If the closure takes a single parameter, the
+     * argument passed will be each element, and the closure
+     * should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the List
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b {@code ->} a {@code <=>} b }</pre>
      *
-     * @param self         an Iterator
-     * @param initialValue some initial value
-     * @param closure      a closure
-     * @return the result of the last closure call
-     * @see #inject(Collection, Object, Closure)
-     * @since 1.5.0
+     * @param self    a List
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @see #unique(Collection, boolean, Closure)
+     * @since 2.4.0
      */
-    public static <E,T, U extends T, V extends T> T inject(Iterator<E> self, U initialValue, @ClosureParams(value=FromString.class,options="U,E") Closure<V> closure) {
-        T value = initialValue;
-        Object[] params = new Object[2];
-        while (self.hasNext()) {
-            Object item = self.next();
-            params[0] = value;
-            params[1] = item;
-            value = closure.call(params);
-        }
-        return value;
+    public static <T> List<T> unique(List<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, true, closure);
     }
 
     /**
-     * Iterates through the given Object, passing in the first value to
-     * the closure along with the first item. The result is passed back (injected) into
-     * the closure along with the second item. The new result is injected back into
-     * the closure along with the third item and so on until further iteration of
-     * the object is not possible. Also known as foldLeft in functional parlance.
+     * A convenience method for making a collection unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the Collection will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 4, 5]
+     * def uniq = orig.unique(false) { it % 2 }
+     * assert orig == [1, 3, 4, 5]
+     * assert uniq == [1, 4]
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [2, 3, 3, 4]
+     * def uniq = orig.unique(false) { a, b {@code ->} a {@code <=>} b }
+     * assert orig == [2, 3, 3, 4]
+     * assert uniq == [2, 3, 4]
+     * </pre>
      *
-     * @param self         an Object
-     * @param closure      a closure
-     * @return the result of the last closure call
-     * @throws NoSuchElementException if the collection is empty.
-     * @see #inject(Collection, Object, Closure)
-     * @since 1.8.7
+     * @param self    a Collection
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @since 1.8.1
      */
-    @SuppressWarnings("unchecked")
-    public static <T, V extends T> T inject(Object self, Closure<V> closure) {
-        Iterator iter = InvokerHelper.asIterator(self);
-        if( !iter.hasNext() ) {
-            throw new NoSuchElementException( "Cannot call inject() over an empty iterable without passing an initial value." ) ;
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        // use a comparator of one item or two
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            self = unique(self, mutate, new OrderBy<>(closure, true));
+        } else {
+            self = unique(self, mutate, new ClosureComparator<>(closure));
         }
-        Object initialValue = iter.next() ;
-        return (T) inject(iter, initialValue, closure);
+        return self;
     }
 
     /**
-     * Iterates through the given Object, passing in the initial value to
-     * the closure along with the first item. The result is passed back (injected) into
-     * the closure along with the second item. The new result is injected back into
-     * the closure along with the third item and so on until further iteration of
-     * the object is not possible. Also known as foldLeft in functional parlance.
+     * A convenience method for making a List unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the List will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 4, 5]
+     * def uniq = orig.unique(false) { it % 2 }
+     * assert orig == [1, 3, 4, 5]
+     * assert uniq == [1, 4]
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [2, 3, 3, 4]
+     * def uniq = orig.unique(false) { a, b {@code ->} a {@code <=>} b }
+     * assert orig == [2, 3, 3, 4]
+     * assert uniq == [2, 3, 4]
+     * </pre>
      *
-     * @param self         an Object
-     * @param initialValue some initial value
-     * @param closure      a closure
-     * @return the result of the last closure call
-     * @see #inject(Collection, Object, Closure)
-     * @since 1.5.0
+     * @param self    a List
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @since 2.4.0
      */
-    @SuppressWarnings("unchecked")
-    public static <T, U extends T, V extends T> T inject(Object self, U initialValue, Closure<V> closure) {
-        Iterator iter = InvokerHelper.asIterator(self);
-        return (T) inject(iter, initialValue, closure);
+    public static <T> List<T> unique(List<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, mutate, closure);
     }
 
     /**
-     * Sums the items in an Iterable. This is equivalent to invoking the
-     * "plus" method on all items in the Iterable.
-     * <pre class="groovyTestCase">assert 1+2+3+4 == [1,2,3,4].sum()</pre>
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the supplied comparator. The original iterator
+     * will be exhausted upon returning.
      *
-     * @param self Iterable of values to add together
-     * @return The sum of all the items
-     * @see #sum(Iterator)
-     * @since 2.2.0
+     * @param self an Iterator
+     * @param comparator a Comparator
+     * @return the modified Iterator
+     * @since 1.5.5
      */
-    public static Object sum(Iterable<?> self) {
-        return sum(self.iterator(), null, true);
+    public static <T> Iterator<T> unique(Iterator<T> self, Comparator<? super T> comparator) {
+        return uniqueItems(new IteratorIterableAdapter<>(self), comparator).listIterator();
+    }
+
+    private static final class IteratorIterableAdapter<T> implements Iterable<T> {
+        private final Iterator<T> self;
+
+        private IteratorIterableAdapter(Iterator<T> self) {
+            this.self = self;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return self;
+        }
     }
 
     /**
-     * Sums the items from an Iterator. This is equivalent to invoking the
-     * "plus" method on all items from the Iterator. The iterator will become
-     * exhausted of elements after determining the sum value.
+     * Remove all duplicates from a given Collection.
+     * Works on the original object (and also returns it).
+     * The order of members in the Collection are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given Collection's iterator is retained, but all other ones are removed.
+     * The given Collection's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self an Iterator for the values to add together
-     * @return The sum of all the items
-     * @since 1.5.5
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(new PersonComparator())
+     * assert( list2 == list {@code &&} list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a Collection
+     * @param comparator a Comparator
+     * @return self      the now modified collection without duplicates
+     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
+     * @since 1.0
      */
-    public static Object sum(Iterator<Object> self) {
-        return sum(self, null, true);
+    public static <T> Collection<T> unique(Collection<T> self, Comparator<? super T> comparator) {
+        return unique(self, true, comparator) ;
     }
 
     /**
-     * Sums the items in an Iterable, adding the result to some initial value.
+     * Remove all duplicates from a given List.
+     * Works on the original object (and also returns it).
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
      * <pre class="groovyTestCase">
-     * assert 5+1+2+3+4 == [1,2,3,4].sum(5)
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(new PersonComparator())
+     * assert( list2 == list {@code &&} list == [a, b, c] )
      * </pre>
      *
-     * @param self         an Iterable of values to sum
-     * @param initialValue the items in the collection will be summed to this initial value
-     * @return The sum of all the items.
-     * @see #sum(Iterator, Object)
-     * @since 2.2.0
+     * @param self       a List
+     * @param comparator a Comparator
+     * @return self      the now modified List without duplicates
+     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
+     * @since 2.4.0
      */
-    public static Object sum(Iterable<?> self, Object initialValue) {
-        return sum(self.iterator(), initialValue, false);
+    public static <T> List<T> unique(List<T> self, Comparator<? super T> comparator) {
+        return (List<T>) unique((Collection<T>) self, true, comparator);
     }
 
     /**
-     * Sums the items from an Iterator, adding the result to some initial value. This is
-     * equivalent to invoking the "plus" method on all items from the Iterator. The iterator
-     * will become exhausted of elements after determining the sum value.
+     * Remove all duplicates from a given Collection.
+     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new collection is returned.
+     * The order of members in the Collection are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given Collection's iterator is retained, but all other ones are removed.
+     * The given Collection's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self         an Iterator for the values to add together
-     * @param initialValue the items in the collection will be summed to this initial value
-     * @return The sum of all the items
-     * @since 1.5.5
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(false, new PersonComparator())
+     * assert( list2 != list {@code &&} list2 == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a Collection
+     * @param mutate     false will always cause a new collection to be created, true will mutate collections in place
+     * @param comparator a Comparator
+     * @return self      the collection without duplicates
+     * @since 1.8.1
      */
-    public static Object sum(Iterator<?> self, Object initialValue) {
-        return sum(self, initialValue, false);
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, Comparator<? super T> comparator) {
+        List<T> answer = uniqueItems(self, comparator);
+        if (mutate) {
+            self.clear();
+            self.addAll(answer);
+        }
+        return mutate ? self : answer;
     }
 
-    static Object sum(Iterator<?> self, Object initialValue, boolean first) {
-        Object result = initialValue;
-        Object[] param = new Object[1];
-        while (self.hasNext()) {
-            Object next = self.next();
-            param[0] = next;
-            if (first) {
-                result = param[0];
-                first = false;
-                continue;
+    private static <T> List<T> uniqueItems(Iterable<T> self, Comparator<? super T> comparator) {
+        List<T> answer = new ArrayList<>();
+        for (T t : self) {
+            boolean duplicated = false;
+            for (T t2 : answer) {
+                if (comparator.compare(t, t2) == 0) {
+                    duplicated = true;
+                    break;
+                }
             }
-            MetaClass metaClass = InvokerHelper.getMetaClass(result);
-            result = metaClass.invokeMethod(result, "plus", param);
+            if (!duplicated)
+                answer.add(t);
         }
-        return result;
+        return answer;
     }
 
     /**
-     * Sums the result of applying a closure to each item of an Iterable.
-     * <code>coll.sum(closure)</code> is equivalent to:
-     * <code>coll.collect(closure).sum()</code>.
-     * <pre class="groovyTestCase">assert 4+6+10+12 == [2,3,5,6].sum { it * 2 }</pre>
+     * Remove all duplicates from a given List.
+     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new List is returned.
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self    an Iterable
-     * @param closure a single parameter closure that returns a (typically) numeric value.
-     * @return The sum of the values returned by applying the closure to each
-     *         item of the Iterable.
-     * @since 2.2.0
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(false, new PersonComparator())
+     * assert( list2 != list {@code &&} list2 == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a List
+     * @param mutate     false will always cause a new List to be created, true will mutate List in place
+     * @param comparator a Comparator
+     * @return self      the List without duplicates
+     * @since 2.4.0
      */
-    public static <T> Object sum(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return sum(self.iterator(), null, closure, true);
+    public static <T> List<T> unique(List<T> self, boolean mutate, Comparator<? super T> comparator) {
+        return (List<T>) unique((Collection<T>) self, mutate, comparator);
     }
 
     /**
-     * Sums the result of applying a closure to each item returned from an iterator.
-     * <code>iter.sum(closure)</code> is equivalent to:
-     * <code>iter.collect(closure).sum()</code>. The iterator will become
-     * exhausted of elements after determining the sum value.
+     * Returns an iterator equivalent to this iterator but with all duplicated items
+     * removed where duplicate (equal) items are deduced by calling the supplied Closure condition.
+     * <p>
+     * If the supplied Closure takes a single parameter, the argument passed will be each element,
+     * and the closure should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the Iterator
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def items = "Hello".toList() + [null, null] + "there".toList()
+     * def toLower = { it == null ? null : it.toLowerCase() }
+     * def noDups = items.iterator().toUnique(toLower).toList()
+     * assert noDups == ['H', 'e', 'l', 'o', null, 't', 'r']
+     * </pre>
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].toUnique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].toUnique { a, b {@code ->} a {@code <=>} b }</pre>
      *
-     * @param self    An Iterator
-     * @param closure a single parameter closure that returns a (typically) numeric value.
-     * @return The sum of the values returned by applying the closure to each
-     *         item from the Iterator.
-     * @since 1.7.1
+     * @param self an Iterator
+     * @param condition a Closure used to determine unique items
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> Object sum(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return sum(self, null, closure, true);
+    public static <T> Iterator<T> toUnique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        return toUnique(self, condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<>(condition, true)
+                : new ClosureComparator<>(condition));
+    }
+
+    private static final class ToUniqueIterator<E> implements Iterator<E> {
+        private final Iterator<E> delegate;
+        private final Set<E> seen;
+        private boolean exhausted;
+        private E next;
+
+        private ToUniqueIterator(Iterator<E> delegate, Comparator<? super E> comparator) {
+            this.seen = new TreeSet<>(comparator);
+            this.delegate = delegate;
+            advance();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return !exhausted;
+        }
+
+        @Override
+        public E next() {
+            if (exhausted) throw new NoSuchElementException();
+            E result = next;
+            advance();
+            return result;
+        }
+
+        @Override
+        public void remove() {
+            if (exhausted) throw new NoSuchElementException();
+            delegate.remove();
+        }
+
+        private void advance() {
+            boolean foundNext = false;
+            while (!foundNext && !exhausted) {
+                exhausted = !delegate.hasNext();
+                if (!exhausted) {
+                    next = delegate.next();
+                    foundNext = seen.add(next);
+                }
+            }
+        }
     }
 
     /**
-     * Sums the result of applying a closure to each item of an Iterable to some initial value.
-     * <code>iter.sum(initVal, closure)</code> is equivalent to:
-     * <code>iter.collect(closure).sum(initVal)</code>.
-     * <pre class="groovyTestCase">assert 50+4+6+10+12 == [2,3,5,6].sum(50) { it * 2 }</pre>
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the supplied comparator.
      *
-     * @param self         an Iterable
-     * @param closure      a single parameter closure that returns a (typically) numeric value.
-     * @param initialValue the closure results will be summed to this initial value
-     * @return The sum of the values returned by applying the closure to each
-     *         item of the collection.
-     * @since 1.5.0
+     * @param self an Iterator
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> Object sum(Iterable<T> self, Object initialValue, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return sum(self.iterator(), initialValue, closure, false);
+    public static <T> Iterator<T> toUnique(Iterator<T> self, Comparator<? super T> comparator) {
+        return new ToUniqueIterator<>(self, comparator);
     }
 
     /**
-     * Sums the result of applying a closure to each item of an Iterator to some initial value.
-     * <code>iter.sum(initVal, closure)</code> is equivalent to:
-     * <code>iter.collect(closure).sum(initVal)</code>. The iterator will become
-     * exhausted of elements after determining the sum value.
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the natural ordering of the items.
      *
-     * @param self         an Iterator
-     * @param closure      a single parameter closure that returns a (typically) numeric value.
-     * @param initialValue the closure results will be summed to this initial value
-     * @return The sum of the values returned by applying the closure to each
-     *         item from the Iterator.
-     * @since 1.7.1
+     * @param self an Iterator
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> Object sum(Iterator<T> self, Object initialValue, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        return sum(self, initialValue, closure, false);
+    public static <T> Iterator<T> toUnique(Iterator<T> self) {
+        return toUnique(self, (Comparator<T>) null);
     }
 
-    static Object sum(Iterator<?> self, Object initialValue, Closure closure, boolean first) {
-        Object result = initialValue;
-        Object[] closureParam = new Object[1];
-        Object[] plusParam = new Object[1];
-        while (self.hasNext()) {
-            closureParam[0] = self.next();
-            plusParam[0] = closure.call(closureParam);
-            if (first) {
-                result = plusParam[0];
-                first = false;
-                continue;
-            }
-            MetaClass metaClass = InvokerHelper.getMetaClass(result);
-            result = metaClass.invokeMethod(result, "plus", plusParam);
-        }
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert list2 == [a, b, c] {@code &&} list == [a, b, c, d]
+     * </pre>
+     *
+     * @param self       an Iterable
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self, Comparator<? super T> comparator) {
+        Collection<T> result = createSimilarCollection(self);
+        addAll(result, toUnique(self.iterator(), comparator));
         return result;
     }
 
     /**
-     * Concatenates the <code>toString()</code> representation of each item from
-     * the Iterator, with the given String as a separator between each item. The
-     * iterator will become exhausted of elements after producing the resulting
-     * conjoined value.
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * List is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self      an Iterator of objects
-     * @param separator a String separator
-     * @return the joined String
-     * @since 1.5.5
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert list2 == [a, b, c] {@code &&} list == [a, b, c, d]
+     * </pre>
+     *
+     * @param self       a List
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the List of non-duplicate items
+     * @since 2.4.0
      */
-    public static String join(final Iterator<?> self, final String separator) {
-        StringJoiner joiner = new StringJoiner(separator != null ? separator : "");
-        while (self.hasNext()) {
-            Object obj = self.next();
-            String str = FormatHelper.toString(obj);
-            joiner.add(str);
-        }
-        return joiner.toString();
+    public static <T> List<T> toUnique(List<T> self, Comparator<? super T> comparator) {
+        return (List<T>) toUnique((Iterable<T>) self, comparator);
     }
 
     /**
-     * Concatenates the <code>toString()</code> representation of each item from
-     * the Iterable, with the given String as a separator between each item.
+     * Returns a Collection containing the items from the Iterable but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
      * <p>
-     * <pre class="groovyTestCase">assert [1,2,3].join() == "123"</pre>
-     * <pre class="groovyTestCase">assert [1,2,3].join(", ") == "1, 2, 3"</pre>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
      *
-     * @param self      an Iterable of objects
-     * @param separator a String separator
-     * @return the joined String
-     * @since 1.0
+     * @param self       an Iterable
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
      */
-    public static String join(final Iterable<?> self, final String separator) {
-        return join(self.iterator(), separator);
+    public static <T> Collection<T> toUnique(Iterable<T> self) {
+        return toUnique(self, (Comparator<T>) null);
     }
 
     /**
-     * Adds min() method to Collection objects.
-     * <pre class="groovyTestCase">assert 2 == [4,2,5].min()</pre>
+     * Returns a List containing the items from the List but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
+     * <p>
+     * <pre class="groovyTestCase">
+     * def letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * def expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
      *
-     * @param self a Collection
-     * @return the minimum value
-     * @see #min(Iterator)
-     * @since 1.0
+     * @param self       a List
+     * @return the List of non-duplicate items
+     * @since 2.4.0
      */
-    public static <T> T min(Iterable<T> self) {
-        return min(self.iterator());
+    public static <T> List<T> toUnique(List<T> self) {
+        return toUnique(self, (Comparator<T>) null);
     }
 
     /**
-     * Adds min() method to Iterator objects. The iterator will become
-     * exhausted of elements after determining the minimum value.
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self an Iterator
-     * @return the minimum value
-     * @see #min(Iterable)
-     * @since 1.5.5
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 {@code ->} p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
+     * assert( list2 == [a, b, c] {@code &&} list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] {@code &&} list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      an Iterable
+     * @param condition a Closure used to determine unique items
+     * @return a new Collection
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
      */
-    public static <T> T min(Iterator<T> self) {
-        T answer = null;
-        while (self.hasNext()) {
-            T value =  self.next();
-            if (value != null && (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer))) {
-                answer = value;
-            }
-        }
-        return answer;
+    public static <T> Collection<T> toUnique(Iterable<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<>(condition, true)
+                : new ClosureComparator<>(condition);
+        return toUnique(self, comparator);
     }
 
     /**
-     * Selects the minimum value found in the Iterable using the given comparator.
-     * <pre class="groovyTestCase">assert "hi" == ["hello","hi","hey"].min( { a, b {@code ->} a.length() {@code <=>} b.length() } as Comparator )</pre>
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self       an Iterable
-     * @param comparator a Comparator
-     * @return the minimum value or null for an empty Iterable
-     * @see #min(Iterator, java.util.Comparator)
-     * @since 2.2.0
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 {@code ->} p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
+     * assert( list2 == [a, b, c] {@code &&} list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] {@code &&} list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      a List
+     * @param condition a Closure used to determine unique items
+     * @return a new List
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
      */
-    public static <T> T min(Iterable<T> self, Comparator<? super T> comparator) {
-        return min(self.iterator(), comparator);
+    public static <T> List<T> toUnique(List<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        return (List<T>) toUnique((Iterable<T>) self, condition);
     }
 
     /**
-     * Selects the minimum value found from the Iterator using the given comparator.
+     * Allows a Map to be iterated through in reverse order using a closure.
      *
-     * @param self       an Iterator
-     * @param comparator a Comparator
-     * @return the minimum value
-     * @since 1.5.5
+     * In general, the order in which the map contents are processed
+     * cannot be guaranteed. In practise, specialized forms of Map,
+     * e.g. a TreeMap will have its contents processed according to the
+     * reverse of the natural ordering of the map.
+     *
+     * @param self    the map over which we iterate
+     * @param closure the 1 or 2 arg closure applied on each entry of the map
+     * @return returns the self parameter
+     * @see #each(Map, Closure)
+     * @since 1.7.2
      */
-    public static <T> T min(Iterator<T> self, Comparator<? super T> comparator) {
-        Objects.requireNonNull(self);
-        T answer = null;
-        boolean first = true;
-        while (self.hasNext()) {
-            T value = self.next();
-            if (first) {
-                first = false;
-                answer = value;
-            } else if (comparator.compare(value, answer) < 0) {
-                answer = value;
-            }
+    @SuppressWarnings("unchecked")
+    public static <K, V> Map<K, V> reverseEach(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<?> closure) {
+        final Iterator<Map.Entry<K, V>> entries = reverse(self.entrySet().iterator());
+        while (entries.hasNext()) {
+            callClosureForMapEntry(closure, entries.next());
         }
-        return answer;
+        return self;
     }
 
     /**
-     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
-     * minimum value. A null return value represents the least possible return value. If more than one item
-     * has the minimum value, an arbitrary choice is made between the items having the minimum value.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">
-     * assert "hi" == ["hello","hi","hey"].min { it.length() }
-     * </pre>
-     * <pre class="groovyTestCase">
-     * def lastDigit = { a, b {@code ->} a % 10 {@code <=>} b % 10 }
-     * assert [19, 55, 91].min(lastDigit) == 91
-     * </pre>
-     * <pre class="groovyTestCase">
-     * def pets = ['dog', 'cat', 'anaconda']
-     * def shortestName = pets.min{ it.size() } // one of 'dog' or 'cat'
-     * assert shortestName.size() == 3
-     * </pre>
+     * Iterate over each element of the list in the reverse order.
+     * <pre class="groovyTestCase">def result = []
+     * [1,2,3].reverseEach { result &lt;&lt; it }
+     * assert result == [3,2,1]</pre>
      *
-     * @param self    an Iterable
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return an item from the Iterable having the minimum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
-     * @see #min(Iterator)
-     * @since 1.0
+     * @param self    a List
+     * @param closure a closure to which each item is passed.
+     * @return the original list
+     * @since 1.5.0
      */
-    public static <T> T min(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return min(self.iterator(), closure);
+    public static <T> List<T> reverseEach(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        each(new ReverseListIterator<>(self), closure);
+        return self;
     }
 
     /**
-     * Selects an entry in the map having the minimum
-     * calculated value as determined by the supplied closure.
-     * If more than one entry has the minimum value,
-     * an arbitrary choice is made between the entries having the minimum value.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">
-     * def zoo = [monkeys:6, lions:5, tigers:7]
-     * def leastCommonEntry = zoo.min{ it.value }
-     * assert leastCommonEntry.value == 5
-     * def mostCommonEntry = zoo.min{ a, b {@code ->} b.value {@code <=>} a.value } // double negative!
-     * assert mostCommonEntry.value == 7
-     * </pre>
-     * Edge case for multiple min values:
+     * Iterate over each element of the set in reverse order.
      * <pre class="groovyTestCase">
-     * def zoo = [monkeys:6, lions:5, tigers:7]
-     * def lastCharOfName = { e {@code ->} e.key[-1] }
-     * def ans = zoo.min(lastCharOfName) // some random entry
-     * assert lastCharOfName(ans) == 's'
+     * TreeSet navSet = [2, 4, 1, 3]  // natural order is sorted
+     * List result = []
+     * navSet.reverseEach { result &lt;&lt; it }
+     * assert result == [4, 3, 2, 1]
      * </pre>
      *
-     * @param self    a Map
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return the Map.Entry having the minimum value as determined by the closure
-     * @since 1.7.6
+     * @param self    a NavigableSet
+     * @param closure a closure to which each item is passed.
+     * @return the original NavigableSet
+     * @since 4.0.11
      */
-    public static <K, V> Map.Entry<K, V> min(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>", "Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
-        return min(self.entrySet(), closure);
+    public static <T> NavigableSet<T> reverseEach(NavigableSet<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        each(self.descendingIterator(), closure);
+        return self;
     }
 
     /**
-     * Selects an entry in the map having the maximum
-     * calculated value as determined by the supplied closure.
-     * If more than one entry has the maximum value,
-     * an arbitrary choice is made between the entries having the maximum value.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison. An example:
-     * <pre class="groovyTestCase">
-     * def zoo = [monkeys:6, lions:5, tigers:7]
-     * def mostCommonEntry = zoo.max{ it.value }
-     * assert mostCommonEntry.value == 7
-     * def leastCommonEntry = zoo.max{ a, b {@code ->} b.value {@code <=>} a.value } // double negative!
-     * assert leastCommonEntry.value == 5
-     * </pre>
-     * Edge case for multiple max values:
-     * <pre class="groovyTestCase">
-     * def zoo = [monkeys:6, lions:5, tigers:7]
-     * def lengthOfNamePlusNumber = { e {@code ->} e.key.size() + e.value }
-     * def ans = zoo.max(lengthOfNamePlusNumber) // one of [monkeys:6, tigers:7]
-     * assert lengthOfNamePlusNumber(ans) == 13
-     * </pre>
+     * Convert an iterator to a List. The iterator will become
+     * exhausted of elements after making this conversion.
      *
-     * @param self    a Map
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return the Map.Entry having the maximum value as determined by the closure
-     * @since 1.7.6
+     * @param self an iterator
+     * @return a List
+     * @since 1.5.0
      */
-    public static <K, V> Map.Entry<K, V> max(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>", "Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
-        return max(self.entrySet(), closure);
-    }
+    public static <T> List<T> toList(Iterator<T> self) {
 
-    /**
-     * Selects the minimum value found from the Iterator
-     * using the closure to determine the correct ordering.
-     * The iterator will become
-     * exhausted of elements after this operation.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     *
-     * @param self    an Iterator
-     * @param closure a Closure used to determine the correct ordering
-     * @return the minimum value
-     * @since 1.5.5
-     */
-    public static <T> T min(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        int params = closure.getMaximumNumberOfParameters();
-        if (params != 1) {
-            return min(self, new ClosureComparator<>(closure));
-        }
-        Objects.requireNonNull(self);
-        boolean first = true;
-        T answer = null;
-        Object answerValue = null;
+        List<T> answer = new ArrayList<>();
         while (self.hasNext()) {
-            T item = self.next();
-            Object value = closure.call(item);
-            if (first) {
-                first = false;
-                answer = item;
-                answerValue = value;
-            } else if (ScriptBytecodeAdapter.compareLessThan(value, answerValue)) {
-                answer = item;
-                answerValue = value;
-            }
+            answer.add(self.next());
         }
         return answer;
     }
 
     /**
-     * Adds max() method to Iterable objects.
-     * <pre class="groovyTestCase">
-     * assert 5 == [2,3,1,5,4].max()
-     * </pre>
+     * Convert an Iterable to a List. The Iterable's iterator will
+     * become exhausted of elements after making this conversion.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">def x = [1,2,3] as HashSet
+     * assert x.class == HashSet
+     * assert x.toList() instanceof List</pre>
      *
      * @param self an Iterable
-     * @return the maximum value
-     * @see #max(Iterator)
-     * @since 2.2.0
+     * @return a List
+     * @since 1.8.7
      */
-    public static <T> T max(Iterable<T> self) {
-        return max(self.iterator());
+    public static <T> List<T> toList(Iterable<T> self) {
+        return toList(self.iterator());
     }
 
     /**
-     * Adds max() method to Iterator objects. The iterator will become
-     * exhausted of elements after determining the maximum value.
+     * Convert an enumeration to a List.
      *
-     * @param self an Iterator
-     * @return the maximum value
-     * @since 1.5.5
+     * @param self an enumeration
+     * @return a List
+     * @since 1.5.0
      */
-    public static <T> T max(Iterator<T> self) {
-        T answer = null;
-        while (self.hasNext()) {
-            T value =  self.next();
-            if (value != null && (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer))) {
-                answer = value;
-            }
+    public static <T> List<T> toList(Enumeration<T> self) {
+        List<T> answer = new ArrayList<>();
+        while (self.hasMoreElements()) {
+            answer.add(self.nextElement());
         }
         return answer;
     }
 
     /**
-     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
-     * maximum value. A null return value represents the least possible return value, so any item for which
-     * the supplied closure returns null, won't be selected (unless all items return null). If more than one item
-     * has the maximum value, an arbitrary choice is made between the items having the maximum value.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert "hello" == ["hello","hi","hey"].max { it.length() }</pre>
-     * <pre class="groovyTestCase">assert "hello" == ["hello","hi","hey"].max { a, b {@code ->} a.length() {@code <=>} b.length() }</pre>
-     * <pre class="groovyTestCase">
-     * def pets = ['dog', 'elephant', 'anaconda']
-     * def longestName = pets.max{ it.size() } // one of 'elephant' or 'anaconda'
-     * assert longestName.size() == 8
-     * </pre>
+     * A variant of withCollectedValues for Iterators.
      *
-     * @param self    an Iterable
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return an item from the Iterable having the maximum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
-     * @since 2.2.0
+     * @param keys           an Iterator
+     * @param collector      the Map into which the transformed entries are put
+     * @param valueTransform a function for transforming Iterator elements into values
+     * @return the collector with all transformed values added to it
+     * @see #withCollectedValues(Iterable, Map, Function)
+     * @since 5.0.0
      */
-    public static <T> T max(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return max(self.iterator(), closure);
+    public static <K, V> Map<K, V> withCollectedValues(Iterator<K> keys, Map<K, V> collector, Function<? super K, V> valueTransform) {
+        return collectEntries(keys, collector, Function.identity(), valueTransform);
     }
 
     /**
-     * Selects the maximum value found from the Iterator
-     * using the closure to determine the correct ordering.
-     * The iterator will become exhausted of elements after this operation.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
+     * A variant of withCollectedValues for Iterators.
      *
-     * @param self    an Iterator
-     * @param closure a Closure used to determine the correct ordering
-     * @return the maximum value
-     * @since 1.5.5
+     * @param keys           an Iterator
+     * @param valueTransform a function for transforming Iterator elements into values
+     * @return a Map of the transformed entries
+     * @see #withCollectedValues(Iterable, Function)
+     * @since 5.0.0
      */
-    public static <T> T max(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        int params = closure.getMaximumNumberOfParameters();
-        if (params != 1) {
-            return max(self, new ClosureComparator<>(closure));
-        }
-        boolean first = true;
-        T answer = null;
-        Object answerValue = null;
-        while (self.hasNext()) {
-            T item = self.next();
-            Object value = closure.call(item);
-            if (first) {
-                first = false;
-                answer = item;
-                answerValue = value;
-            } else if (ScriptBytecodeAdapter.compareLessThan(answerValue, value)) {
-                answer = item;
-                answerValue = value;
-            }
-        }
-        return answer;
+    public static <K, V> Map<K, V> withCollectedValues(Iterator<K> keys, Function<? super K, V> valueTransform) {
+        return withCollectedValues(keys, new LinkedHashMap<>(), valueTransform);
     }
 
     /**
-     * Selects the maximum value found in the Iterable using the given comparator.
+     * Transform Iterable elements into Map entries with keys unchanged
+     * and values transformed using the supplied function.
+     * The supplied collector map is used as the destination for transformed entries.
      * <pre class="groovyTestCase">
-     * assert "hello" == ["hello","hi","hey"].max( { a, b {@code ->} a.length() {@code <=>} b.length() } as Comparator )
+     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
+     * assert languages.withCollectedValues([Clojure:7], String::size) ==
+     *     [Clojure:7, Groovy:6, Java:4, Kotlin:6, Scala:5]
      * </pre>
+     * This method is a convenience method for {@link #collectEntries(Iterable, Map, Function, Function)}
+     * with the {@code keyTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
      *
-     * @param self       an Iterable
-     * @param comparator a Comparator
-     * @return the maximum value or null for an empty Iterable
-     * @see #max(Iterator, Comparator)
-     * @since 2.2.0
+     * @param keys           an Iterable
+     * @param collector      the Map into which the transformed entries are put
+     * @param valueTransform a function for transforming Iterable elements into values
+     * @return the collector with all transformed values added to it
+     * @since 5.0.0
      */
-    public static <T> T max(Iterable<T> self, Comparator<? super T> comparator) {
-        return max(self.iterator(), comparator);
+    public static <K, V> Map<K, V> withCollectedValues(Iterable<K> keys, Map<K, V> collector, Function<? super K, V> valueTransform) {
+        return collectEntries(keys.iterator(), collector, Function.identity(), valueTransform);
     }
 
     /**
-     * Selects the maximum value found from the Iterator using the given comparator.
+     * Transform Iterable elements into Map entries with keys unchanged
+     * and values transformed using the supplied function.
+     * <pre class="groovyTestCase">
+     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
+     * assert languages.withCollectedValues(String::size) ==
+     *     [Groovy:6, Java:4, Kotlin:6, Scala:5]
+     * </pre>
+     * This method is a convenience method for {@link #collectEntries(Iterable, Function, Function)}
+     * with the {@code keyTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
      *
-     * @param self       an Iterator
-     * @param comparator a Comparator
-     * @return the maximum value
-     * @since 1.5.5
+     * @param keys           an Iterable
+     * @param valueTransform a function for transforming Iterable elements into values
+     * @return a Map of the transformed entries
+     * @since 5.0.0
      */
-    public static <T> T max(Iterator<T> self, Comparator<? super T> comparator) {
-        T answer = null;
-        while (self.hasNext()) {
-            T value = self.next();
-            if (value != null && (answer == null || comparator.compare(value, answer) > 0)) {
-                answer = value;
-            }
-        }
-        return answer;
+    public static <K, V> Map<K, V> withCollectedValues(Iterable<K> keys, Function<? super K, V> valueTransform) {
+        return withCollectedValues(keys.iterator(), new LinkedHashMap<>(), valueTransform);
     }
 
     /**
-     * Returns indices of the collection.
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * assert 0..2 == [5, 6, 7].indices
-     * </pre>
+     * A variant of withCollectedKeys for Iterators.
      *
-     * @param self a collection
-     * @return an index range
-     * @since 2.4.0
+     * @param values       an Iterator
+     * @param collector    the Map into which the transformed entries are put
+     * @param keyTransform a function for transforming Iterator elements into values
+     * @return the collector with all transformed values added to it
+     * @see #withCollectedKeys(Iterable, Map, Function)
+     * @since 5.0.0
      */
-    public static IntRange getIndices(Collection self) {
-        return new IntRange(false, 0, self.size());
+    public static <K, V> Map<K, V> withCollectedKeys(Iterator<V> values, Map<K, V> collector, Function<? super V, K> keyTransform) {
+        return collectEntries(values, collector, keyTransform, Function.identity());
     }
 
     /**
-     * Provide the standard Groovy <code>size()</code> method for <code>Iterator</code>.
-     * The iterator will become exhausted of elements after determining the size value.
+     * A variant of withCollectedKeys for Iterators.
      *
-     * @param self an Iterator
-     * @return the length of the Iterator
-     * @since 1.5.5
+     * @param values       an Iterator
+     * @param keyTransform a function for transforming Iterator elements into values
+     * @return a Map of the transformed entries
+     * @see #withCollectedKeys(Iterable, Function)
+     * @since 5.0.0
      */
-    public static int size(Iterator self) {
-        int count = 0;
-        while (self.hasNext()) {
-            self.next();
-            count++;
-        }
-        return count;
+    public static <K, V> Map<K, V> withCollectedKeys(Iterator<V> values, Function<? super V, K> keyTransform) {
+        return withCollectedKeys(values, new LinkedHashMap<>(), keyTransform);
     }
 
     /**
-     * Provide the standard Groovy <code>size()</code> method for <code>Iterable</code>.
+     * Transform Iterable elements into Map entries with values unchanged
+     * and keys transformed using the supplied function.
+     * The supplied map is used as the destination for transformed entries.
      * <pre class="groovyTestCase">
-     * def items = [1, 2, 3]
-     * def iterable = { [ hasNext:{ !items.isEmpty() }, next:{ items.pop() } ] as Iterator } as Iterable
-     * assert iterable.size() == 3
+     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
+     * def firstLetter = s {@code ->} s[0]
+     * assert languages.withCollectedKeys([C:'Clojure'], firstLetter) ==
+     *     [C:'Clojure', G:'Groovy', J:'Java', K:'Kotlin', S:'Scala']
      * </pre>
+     * This method is a convenience method for {@link #collectEntries(Iterable, Map, Function, Function)}
+     * with the {@code valueTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
      *
-     * @param self an Iterable
-     * @return the length of the Iterable
-     * @since 2.3.8
+     * @param values       an Iterable that will become the added entry values
+     * @param collector    the Map into which the transformed entries are put
+     * @param keyTransform a function for transforming Iterator elements into keys
+     * @return the collector with all transformed values added to it
+     * @since 5.0.0
      */
-    public static int size(Iterable self) {
-        return size(self.iterator());
+    public static <K, V> Map<K, V> withCollectedKeys(Iterable<V> values, Map<K, V> collector, Function<? super V, K> keyTransform) {
+        return collectEntries(values.iterator(), collector, keyTransform, Function.identity());
     }
 
     /**
-     * Check whether an <code>Iterable</code> has elements
+     * Transform Iterable elements into Map entries with values unchanged
+     * and keys transformed using the supplied function.
      * <pre class="groovyTestCase">
-     * def items = [1]
-     * def iterable = { [ hasNext:{ !items.isEmpty() }, next:{ items.pop() } ] as Iterator } as Iterable
-     * assert !iterable.isEmpty()
-     * iterable.iterator().next()
-     * assert iterable.isEmpty()
+     * def languages = ['Groovy', 'Java', 'Kotlin', 'Scala']
+     * def firstLetter = s {@code ->} s[0]
+     * assert languages.withCollectedKeys(firstLetter) ==
+     *     [G:'Groovy', J:'Java', K:'Kotlin', S:'Scala']
      * </pre>
+     * This method is a convenience method for {@link #collectEntries(Iterable, Function, Function)}
+     * with the {@code valueTransform} replaced by {@code Function.identity()} or {Closure.IDENTITY}.
      *
-     * @param self an Iterable
-     * @return true if the iterable has no elements, false otherwise
-     * @since 2.5.0
+     * @param values       an Iterable that will become the added entry values
+     * @param keyTransform a function for transforming Iterator elements into keys
+     * @return the collector with all transformed values added to it
+     * @since 5.0.0
      */
-    public static boolean isEmpty(Iterable self) {
-        return !self.iterator().hasNext();
+    public static <K, V> Map<K, V> withCollectedKeys(Iterable<V> values, Function<? super V, K> keyTransform) {
+        return withCollectedKeys(values.iterator(), new LinkedHashMap<>(), keyTransform);
+    }
+
+    /**
+     * Modifies this collection by removing its elements that are contained
+     * within the specified object array.
+     *
+     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
+     * containing items which don't match some criteria while leaving the original collection unchanged.
+     *
+     * @param  self  a Collection to be modified
+     * @param  items array containing elements to be removed from this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @see    Collection#removeAll(Collection)
+     * @since 1.7.2
+     */
+    @SuppressWarnings("unchecked")
+    public static boolean removeAll(Collection self, Object[] items) {
+        Collection pickFrom = new TreeSet(new NumberAwareComparator());
+        pickFrom.addAll(Arrays.asList(items));
+        return self.removeAll(pickFrom);
     }
 
     /**
-     * Support the range subscript operator for a List.
-     * <pre class="groovyTestCase">def list = [1, "a", 4.5, true]
-     * assert list[1..2] == ["a", 4.5]</pre>
+     * Modifies this collection so that it retains only its elements that are contained
+     * in the specified array.  In other words, removes from this collection all of
+     * its elements that are not contained in the specified array.
      *
-     * @param self  a List
-     * @param range a Range indicating the items to get
-     * @return a new list instance based on range borders
+     * See also <code>grep</code> and <code>findAll</code> when wanting to produce a new list
+     * containing items which match some specified items but leaving the original collection unchanged.
      *
-     * @since 1.0
+     * @param  self  a Collection to be modified
+     * @param  items array containing elements to be retained from this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @see    Collection#retainAll(Collection)
+     * @since 1.7.2
      */
-    public static <T> List<T> getAt(List<T> self, Range range) {
-        RangeInfo info = subListBorders(self.size(), range);
-
-        List<T> subList = self.subList(info.from, info.to);
-        if (info.reverse) {
-            subList = reverse(subList);
-        }
-
-        // trying to guess the concrete list type and create a new instance from it
-        List<T> answer = createSimilarList(self, subList.size());
-        answer.addAll(subList);
-
-        return answer;
+    @SuppressWarnings("unchecked")
+    public static boolean retainAll(Collection self, Object[] items) {
+        Collection pickFrom = new TreeSet(new NumberAwareComparator());
+        pickFrom.addAll(Arrays.asList(items));
+        return self.retainAll(pickFrom);
     }
 
     /**
-     * Select a List of items from an eager or lazy List using a Collection to
-     * identify the indices to be selected.
-     * <pre class="groovyTestCase">def list = [].withDefault { 42 }
-     * assert list[1,0,2] == [42, 42, 42]</pre>
+     * Modifies this collection so that it retains only its elements
+     * that are matched according to the specified closure condition.  In other words,
+     * removes from this collection all of its elements that don't match.
      *
-     * @param self    a ListWithDefault
-     * @param indices a Collection of indices
+     * <pre class="groovyTestCase">def list = ['a', 'b']
+     * list.retainAll { it == 'b' }
+     * assert list == ['b']</pre>
      *
-     * @return a new eager or lazy list of the values at the given indices
+     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
+     * containing items which match some criteria but leaving the original collection unchanged.
+     *
+     * @param  self      a Collection to be modified
+     * @param  condition a closure condition
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @see    Iterator#remove()
+     * @since 1.7.2
      */
-    @SuppressWarnings("unchecked")
-    public static <T> List<T> getAt(ListWithDefault<T> self, Collection indices) {
-        List<T> answer = ListWithDefault.newInstance(new ArrayList<>(indices.size()), self.isLazyDefaultValues(), self.getInitClosure());
-        for (Object value : indices) {
-            if (value instanceof Collection) {
-                answer.addAll((List<T>) InvokerHelper.invokeMethod(self, "getAt", value));
-            } else {
-                int idx = normaliseIndex(DefaultTypeTransformation.intUnbox(value), self.size());
-                answer.add(self.getAt(idx));
+    public static <T> boolean retainAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        Iterator iter = InvokerHelper.asIterator(self);
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
+        boolean result = false;
+        while (iter.hasNext()) {
+            Object value = iter.next();
+            if (!bcw.call(value)) {
+                iter.remove();
+                result = true;
             }
         }
-        return answer;
+        return result;
     }
 
     /**
-     * Support the range subscript operator for an eager or lazy List.
-     * <pre class="groovyTestCase">def list = [].withDefault { 42 }
-     * assert list[1..2] == [null, 42]</pre>
+     * Modifies this map so that it retains only its elements that are matched
+     * according to the specified closure condition.  In other words, removes from
+     * this map all of its elements that don't match. If the closure takes one
+     * parameter then it will be passed the <code>Map.Entry</code>. Otherwise the closure should
+     * take two parameters, which will be the key and the value.
      *
-     * @param self  a ListWithDefault
-     * @param range a Range indicating the items to get
+     * <pre class="groovyTestCase">def map = [a:1, b:2]
+     * map.retainAll { k,v {@code ->} k == 'b' }
+     * assert map == [b:2]</pre>
      *
-     * @return a new eager or lazy list instance based on range borders
+     * See also <code>findAll</code> when wanting to produce a new map containing items
+     * which match some criteria but leaving the original map unchanged.
+     *
+     * @param self a Map to be modified
+     * @param condition a 1 or 2 arg Closure condition applying on the entries
+     * @return <tt>true</tt> if this map changed as a result of the call
+     * @since 2.5.0
      */
-    public static <T> List<T> getAt(ListWithDefault<T> self, Range range) {
-        RangeInfo info = subListBorders(self.size(), range);
-
-        // if a positive index is accessed not initialized so far
-        // initialization up to that index takes place
-        if (self.size() < info.to) {
-            self.get(info.to - 1);
-        }
-
-        List<T> answer = self.subList(info.from, info.to);
-        if (info.reverse) {
-            answer =  ListWithDefault.newInstance(reverse(answer), self.isLazyDefaultValues(), self.getInitClosure());
-        } else {
-            // instead of using the SubList backed by the parent list, a new ArrayList instance is used
-            answer =  ListWithDefault.newInstance(new ArrayList<>(answer), self.isLazyDefaultValues(), self.getInitClosure());
+    public static <K, V> boolean retainAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure condition) {
+        Iterator<Map.Entry<K, V>> iter = self.entrySet().iterator();
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(condition);
+        boolean result = false;
+        while (iter.hasNext()) {
+            Map.Entry<K, V> entry = iter.next();
+            if (!bcw.callForMap(entry)) {
+                iter.remove();
+                result = true;
+            }
         }
-
-        return answer;
+        return result;
     }
 
     /**
-     * Support the range subscript operator for an eager or lazy List.
-     * <pre class="groovyTestCase">
-     * def list = [true, 1, 3.4].withDefault{ 42 }
-     * {@code assert list[0..<0] == []}
-     * </pre>
+     * Modifies this collection by removing the elements that are matched according
+     * to the specified closure condition.
      *
-     * @param self  a ListWithDefault
-     * @param range a Range indicating the items to get
+     * <pre class="groovyTestCase">def list = ['a', 'b']
+     * list.removeAll { it == 'b' }
+     * assert list == ['a']</pre>
      *
-     * @return a new list instance based on range borders
+     * See also <code>findAll</code> and <code>grep</code> when wanting to produce a new list
+     * containing items which match some criteria but leaving the original collection unchanged.
      *
+     * @param  self a Collection to be modified
+     * @param  condition a closure condition
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @see    Iterator#remove()
+     * @since 1.7.2
      */
-    public static <T> List<T> getAt(ListWithDefault<T> self, EmptyRange range) {
-        return ListWithDefault.newInstance(new ArrayList<>(), self.isLazyDefaultValues(), self.getInitClosure());
+    public static <T> boolean removeAll(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return self.removeIf(new BooleanClosurePredicate<>(condition));
     }
 
     /**
-     * Support the range subscript operator for a List.
-     * <pre class="groovyTestCase">
-     * def list = [true, 1, 3.4]
-     * {@code assert list[0..<0] == []}
-     * </pre>
+     * Modifies this map by removing the elements that are matched according to the
+     * specified closure condition. If the closure takes one parameter then it will be
+     * passed the <code>Map.Entry</code>. Otherwise the closure should take two parameters, which
+     * will be the key and the value.
      *
-     * @param self  a List
-     * @param range a Range indicating the items to get
-     * @return a new list instance based on range borders
+     * <pre class="groovyTestCase">def map = [a:1, b:2]
+     * map.removeAll { k,v {@code ->} k == 'b' }
+     * assert map == [a:1]</pre>
      *
-     * @since 1.0
+     * See also <code>findAll</code> when wanting to produce a new map containing items
+     * which match some criteria but leaving the original map unchanged.
+     *
+     * @param self a Map to be modified
+     * @param condition a 1 or 2 arg Closure condition applying on the entries
+     * @return <tt>true</tt> if this map changed as a result of the call
+     * @since 2.5.0
      */
-    public static <T> List<T> getAt(List<T> self, EmptyRange range) {
-        return createSimilarList(self, 0);
+    public static <K, V> boolean removeAll(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure condition) {
+        return self.entrySet().removeIf(new BooleanClosureForMapPredicate<>(condition));
     }
 
     /**
-     * Select a List of items from a List using a Collection to
-     * identify the indices to be selected.
-     * <pre class="groovyTestCase">def list = [true, 1, 3.4, false]
-     * assert list[1,0,2] == [1, true, 3.4]</pre>
+     * Splits all items into two lists based on the closure condition.
+     * The first list contains all items matching the closure expression.
+     * The second list all those that don't.
      *
-     * @param self    a List
-     * @param indices a Collection of indices
-     * @return a new list of the values at the given indices
-     * @since 1.0
+     * @param self    an Object with an Iterator returning its values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 1.6.0
      */
     @SuppressWarnings("unchecked")
-    public static <T> List<T> getAt(List<T> self, Collection indices) {
-        List<T> answer = new ArrayList<>(indices.size());
-        for (Object value : indices) {
-            if (value instanceof Collection) {
-                answer.addAll(getAt(self, (Collection) value));
-            } else {
-                int idx = DefaultTypeTransformation.intUnbox(value);
-                answer.add(getAt(self, idx));
-            }
-        }
-        return answer;
+    public static Collection split(Object self, Closure closure) {
+        List accept = new ArrayList();
+        List reject = new ArrayList();
+        return split(closure, accept, reject, InvokerHelper.asIterator(self));
     }
 
     /**
-     * Creates a sub-Map containing the given keys. This method is similar to
-     * List.subList() but uses keys rather than index ranges.
-     * <pre class="groovyTestCase">assert [1:10, 2:20, 4:40].subMap( [2, 4] ) == [2:20, 4:40]</pre>
+     * Splits all items into two collections based on the closure condition.
+     * The first list contains all items which match the closure expression.
+     * The second list all those that don't.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">assert [[2,4],[1,3]] == [1,2,3,4].split { it % 2 == 0 }</pre>
      *
-     * @param map  a Map
-     * @param keys a Collection of keys
-     * @return a new Map containing the given keys
-     * @since 1.0
+     * @param self    a Collection of values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 1.6.0
      */
-    public static <K, V> Map<K, V> subMap(Map<K, V> map, Collection<K> keys) {
-        Map<K, V> answer = new LinkedHashMap<>(keys.size());
-        for (K key : keys) {
-            if (map.containsKey(key)) {
-                answer.put(key, map.get(key));
+    public static <T> Collection<Collection<T>> split(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        Collection<T> accept = createSimilarCollection(self);
+        Collection<T> reject = createSimilarCollection(self);
+        Iterator<T> iter = self.iterator();
+        return split(closure, accept, reject, iter);
+    }
+
+    static <T> Collection<Collection<T>> split(Closure closure, Collection<T> accept, Collection<T> reject, Iterator<T> iter) {
+        List<Collection<T>> answer = new ArrayList<>();
+        BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+        while (iter.hasNext()) {
+            T value = iter.next();
+            if (bcw.call(value)) {
+                accept.add(value);
+            } else {
+                reject.add(value);
             }
         }
+        answer.add(accept);
+        answer.add(reject);
         return answer;
     }
 
     /**
-     * Creates a sub-Map containing the given keys. This method is similar to
-     * List.subList() but uses keys rather than index ranges. The original
-     * map is unaltered.
-     * <pre class="groovyTestCase">
-     * def orig = [1:10, 2:20, 3:30, 4:40]
-     * assert orig.subMap([1, 3] as int[]) == [1:10, 3:30]
-     * assert orig.subMap([2, 4] as Integer[]) == [2:20, 4:40]
-     * assert orig.size() == 4
-     * </pre>
+     * Splits all items into two collections based on the closure condition.
+     * The first list contains all items which match the closure expression.
+     * The second list all those that don't.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">assert [[2,4],[1,3]] == [1,2,3,4].split { it % 2 == 0 }</pre>
+     *
+     * @param self    a List of values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 2.4.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List<List<T>> split(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<List<T>>) (List<?>) split((Collection<T>) self, closure);
+    }
+
+    /**
+     * Splits all items into two collections based on the closure condition.
+     * The first list contains all items which match the closure expression.
+     * The second list all those that don't.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">assert [[2,4] as Set, [1,3] as Set] == ([1,2,3,4] as Set).split { it % 2 == 0 }</pre>
      *
-     * @param map  a Map
-     * @param keys an array of keys
-     * @return a new Map containing the given keys
-     * @since 2.1.0
+     * @param self    a Set of values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 2.4.0
      */
-    public static <K, V> Map<K, V> subMap(Map<K, V> map, K[] keys) {
-        Map<K, V> answer = new LinkedHashMap<>(keys.length);
-        for (K key : keys) {
-            if (map.containsKey(key)) {
-                answer.put(key, map.get(key));
-            }
-        }
-        return answer;
+    @SuppressWarnings("unchecked")
+    public static <T> List<Set<T>> split(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<Set<T>>) (List<?>) split((Collection<T>) self, closure);
     }
 
     /**
-     * Looks up an item in a Map for the given key and returns the corresponding value.
-     * If there is no entry for the given key return instead the default value and
-     * also add the key and default value to the map.
-     * <pre class="groovyTestCase">
-     * def map=[:]
-     * map.get("a", []) &lt;&lt; 5
-     * assert map == [a:[5]]
-     * </pre>
-     * For a method which doesn't mutate the map, consider instead using {@link Map#getOrDefault(Object, Object)}
-     * or consider using Groovy's {@link MapWithDefault} often instantiated using {@link #withDefault(Map, Closure)}
-     * or with more options {@link #withDefault(Map, boolean, boolean, Closure)}.
+     * Finds all non-null subsequences of a list.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">def result = [1, 2, 3].subsequences()
+     * assert result == [[1, 2, 3], [1, 3], [2, 3], [1, 2], [1], [2], [3]] as Set</pre>
      *
-     * @param map          a Map
-     * @param key          the key to look up the value
-     * @param defaultValue the value to return and add to the map for this key if
-     *                     there is no entry for the given key
-     * @return the value of the given key or the default value, added to the map if the
-     *         key did not exist
-     * @since 1.0
+     * @param self the List of items
+     * @return the subsequences from the list
+     * @since 1.7.0
      */
-    public static <K, V> V get(Map<K, V> map, K key, V defaultValue) {
-        if (!map.containsKey(key)) {
-            map.put(key, defaultValue);
-        }
-        return map.get(key);
+    public static <T> Set<List<T>> subsequences(List<T> self) {
+        return GroovyCollections.subsequences(self);
     }
 
     /**
-     * Support the subscript operator for a List.
-     * <pre class="groovyTestCase">def list = [2, "a", 5.3]
-     * assert list[1] == "a"</pre>
+     * Finds all permutations of an iterable.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">def result = [1, 2, 3].permutations()
+     * assert result == [[3, 2, 1], [3, 1, 2], [1, 3, 2], [2, 3, 1], [2, 1, 3], [1, 2, 3]] as Set</pre>
      *
-     * @param self a List
-     * @param idx  an index
-     * @return the value at the given index
-     * @since 1.0
+     * @param self the Iterable of items
+     * @return the permutations from the list
+     * @since 1.7.0
      */
-    public static <T> T getAt(List<T> self, int idx) {
-        int size = self.size();
-        int i = normaliseIndex(idx, size);
-        if (i < size) {
-            return self.get(i);
-        } else {
-            return null;
+    public static <T> Set<List<T>> permutations(Iterable<T> self) {
+        Set<List<T>> ans = new HashSet<>();
+        PermutationGenerator<T> generator = new PermutationGenerator<>(self);
+        while (generator.hasNext()) {
+            ans.add(generator.next());
         }
+        return ans;
     }
 
     /**
-     * Support subscript operator for list access.
+     * Finds all permutations of an iterable, applies a function to each permutation and collects the result
+     * into a list.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">Set result = [1, 2, 3].permutations { it.collect { v {@code ->} 2*v }}
+     * assert result == [[6, 4, 2], [6, 2, 4], [2, 6, 4], [4, 6, 2], [4, 2, 6], [2, 4, 6]] as Set</pre>
+     *
+     * @param self the Iterable of items
+     * @param function the function to apply on each permutation
+     * @return the list of results of the application of the function on each permutation
+     * @since 2.2.0
      */
-    public static <T> T getAt(List<T> self, Number idx) {
-        return getAt(self, idx.intValue());
+    public static <T,V> List<V> permutations(Iterable<T> self, Closure<V> function) {
+        return collect(permutations(self), function);
     }
 
     /**
-     * Support the subscript operator for an Iterator. The iterator
-     * will be partially exhausted up until the idx entry after returning
-     * if a +ve or 0 idx is used, or fully exhausted if a -ve idx is used
-     * or no corresponding entry was found. Typical usage:
+     * Adds GroovyCollections#transpose(List) as a method on lists.
+     * A Transpose Function takes a collection of columns and returns a collection of
+     * rows. The first row consists of the first element from each column. Successive
+     * rows are constructed similarly.
+     * <p>
+     * Example usage:
      * <pre class="groovyTestCase">
-     * def iter = [2, "a", 5.3].iterator()
-     * assert iter[1] == "a"
+     * def result = [['a', 'b'], [1, 2]].transpose()
+     * assert result == [['a', 1], ['b', 2]]
      * </pre>
-     * A more elaborate example:
      * <pre class="groovyTestCase">
-     * def items = [2, "a", 5.3]
-     * def iter = items.iterator()
-     * assert iter[-1] == 5.3
-     * // iter exhausted, so reset
-     * iter = items.iterator()
-     * assert iter[1] == "a"
-     * // iter partially exhausted so now idx starts after "a"
-     * assert iter[0] == 5.3
+     * def result = [['a', 'b'], [1, 2], [3, 4]].transpose()
+     * assert result == [['a', 1, 3], ['b', 2, 4]]
      * </pre>
      *
-     * @param self an Iterator
-     * @param idx  an index value (-self.size() &lt;= idx &lt; self.size())
-     * @return the value at the given index (after normalisation) or null if no corresponding value was found
-     * @since 1.7.2
+     * @param self a List of lists
+     * @return a List of the transposed lists
+     * @see groovy.util.GroovyCollections#transpose(java.util.List)
+     * @since 1.5.0
      */
-    public static <T> T getAt(Iterator<T> self, int idx) {
-        if (idx < 0) {
-            // calculate whole list in this case
-            // recommend avoiding -ve's as this is not as efficient
-            List<T> list = toList(self);
-            int adjustedIndex = idx + list.size();
-            if (adjustedIndex < 0 || adjustedIndex >= list.size()) return null;
-            return list.get(adjustedIndex);
+    public static List transpose(List self) {
+        return GroovyCollections.transpose(self);
+    }
+
+    // internal helper method
+    protected static <T, K, V> T callClosureForMapEntry(@ClosureParams(value=FromString.class, options={"K,V","Map.Entry<K,V>"}) Closure<T> closure, Map.Entry<K,V> entry) {
+        if (closure.getMaximumNumberOfParameters() == 2) {
+            return closure.call(entry.getKey(), entry.getValue());
         }
+        return closure.call(entry);
+    }
 
-        int count = 0;
-        while (self.hasNext()) {
-            if (count == idx) {
-                return self.next();
-            } else {
-                count++;
-                self.next();
-            }
+    // internal helper method
+    protected static <T> T callClosureForLine(@ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure, String line, int counter) {
+        if (closure.getMaximumNumberOfParameters() == 2) {
+            return closure.call(line, counter);
         }
+        return closure.call(line);
+    }
 
-        return null;
+    // internal helper method
+    protected static <T, K, V> T callClosureForMapEntryAndCounter(@ClosureParams(value=FromString.class, options={"K,V,Integer", "K,V","Map.Entry<K,V>"}) Closure<T> closure, Map.Entry<K,V> entry, int counter) {
+        if (closure.getMaximumNumberOfParameters() == 3) {
+            return closure.call(entry.getKey(), entry.getValue(), counter);
+        }
+        if (closure.getMaximumNumberOfParameters() == 2) {
+            return closure.call(entry, counter);
+        }
+        return closure.call(entry);
     }
 
     /**
-     * Support the subscript operator for an Iterable. Typical usage:
+     * Performs the same function as the version of inject that takes an initial value, but
+     * uses the head of the Collection as the initial value, and iterates over the tail.
      * <pre class="groovyTestCase">
-     * // custom Iterable example:
-     * class MyIterable implements Iterable {
-     *   Iterator iterator() { [1, 2, 3].iterator() }
-     * }
-     * def myIterable = new MyIterable()
-     * assert myIterable[1] == 2
-     *
-     * // Set example:
-     * def set = [1,2,3] as LinkedHashSet
-     * assert set[1] == 2
+     * assert 1 * 2 * 3 * 4 == [ 1, 2, 3, 4 ].inject { acc, val {@code ->} acc * val }
+     * assert ['b'] == [['a','b'], ['b','c'], ['d','b']].inject { acc, val {@code ->} acc.intersect( val ) }
+     * LinkedHashSet set = [ 't', 'i', 'm' ]
+     * assert 'tim' == set.inject { a, b {@code ->} a + b }
      * </pre>
      *
-     * @param self an Iterable
-     * @param idx  an index value (-self.size() &lt;= idx &lt; self.size()) but using -ve index values will be inefficient
-     * @return the value at the given index (after normalisation) or null if no corresponding value was found
-     * @since 2.1.0
-     */
-    public static <T> T getAt(Iterable<T> self, int idx) {
-        return getAt(self.iterator(), idx);
-    }
-
-    /**
-     * A helper method to allow lists to work with subscript operators.
-     * <pre class="groovyTestCase">def list = [2, 3]
-     * list[0] = 1
-     * assert list == [1, 3]</pre>
-     *
-     * @param self  a List
-     * @param idx   an index
-     * @param value the value to put at the given index
-     * @since 1.0
+     * @param self         a Collection
+     * @param closure      a closure
+     * @return the result of the last closure call
+     * @throws NoSuchElementException if the collection is empty.
+     * @see #inject(Collection, Object, Closure)
+     * @since 1.8.7
      */
-    public static <T> void putAt(List<T> self, int idx, T value) {
-        int size = self.size();
-        idx = normaliseIndex(idx, size);
-        if (idx < size) {
-            self.set(idx, value);
-        } else {
-            while (size < idx) {
-                self.add(size++, null);
-            }
-            self.add(idx, value);
+    @SuppressWarnings("unchecked")
+    public static <T, V extends T> T inject(Collection<T> self, @ClosureParams(value=FromString.class,options="V,T") Closure<V> closure ) {
+        if( self.isEmpty() ) {
+            throw new NoSuchElementException( "Cannot call inject() on an empty collection without passing an initial value." ) ;
+        }
+        Iterator<T> iter = self.iterator();
+        T head = iter.next();
+        Collection<T> tail = tail(self);
+        if (!tail.iterator().hasNext()) {
+            return head;
         }
+        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
+        return (T) inject((Collection) tail, head, closure);
     }
 
     /**
-     * Support subscript operator for list modification.
-     */
-    public static <T> void putAt(List<T> self, Number idx, T value) {
-        putAt(self, idx.intValue(), value);
-    }
-
-    /**
-     * A helper method to allow lists to work with subscript operators.
+     * Iterates through the given Collection, passing in the initial value to
+     * the 2-arg closure along with the first item. The result is passed back (injected) into
+     * the closure along with the second item. The new result is injected back into
+     * the closure along with the third item and so on until the entire collection
+     * has been used. Also known as <tt>foldLeft</tt> or <tt>reduce</tt> in functional parlance.
+     *
+     * Examples:
      * <pre class="groovyTestCase">
-     * def list = ["a", true]
-     * {@code list[1..<1] = 5}
-     * assert list == ["a", 5, true]
+     * assert 1*1*2*3*4 == [1,2,3,4].inject(1) { acc, val {@code ->} acc * val }
+     *
+     * assert 0+1+2+3+4 == [1,2,3,4].inject(0) { acc, val {@code ->} acc + val }
+     *
+     * assert 'The quick brown fox' ==
+     *     ['quick', 'brown', 'fox'].inject('The') { acc, val {@code ->} acc + ' ' + val }
+     *
+     * assert 'bat' ==
+     *     ['rat', 'bat', 'cat'].inject('zzz') { min, next {@code ->} next {@code <} min ? next : min }
+     *
+     * def max = { a, b {@code ->} [a, b].max() }
+     * def animals = ['bat', 'rat', 'cat']
+     * assert 'rat' == animals.inject('aaa', max)
+     * </pre>
+     * Visual representation of the last example above:
+     * <pre>
+     *    initVal  animals[0]
+     *       v        v
+     * max('aaa',   'bat')  {@code =>}  'bat'  animals[1]
+     *                            v       v
+     *                      max('bat',  'rat')  {@code =>}  'rat'  animals[2]
+     *                                                v       v
+     *                                          max('rat',  'cat')  {@code =>}  'rat'
      * </pre>
      *
-     * @param self  a List
-     * @param range the (in this case empty) subset of the list to set
-     * @param value the values to put at the given sublist or a Collection of values
+     * @param self         a Collection
+     * @param initialValue some initial value
+     * @param closure      a closure
+     * @return the result of the last closure call
      * @since 1.0
      */
     @SuppressWarnings("unchecked")
-    public static void putAt(List self, EmptyRange range, Object value) {
-        RangeInfo info = subListBorders(self.size(), range);
-        List sublist = self.subList(info.from, info.to);
-        sublist.clear();
-        if (value instanceof Collection) {
-            Collection col = (Collection) value;
-            if (col.isEmpty()) return;
-            sublist.addAll(col);
-        } else {
-            sublist.add(value);
-        }
+    public static <E, T, U extends T, V extends T> T inject(Collection<E> self, U initialValue, @ClosureParams(value=FromString.class,options="U,E") Closure<V> closure) {
+        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
+        return (T) inject((Iterator) self.iterator(), initialValue, closure);
     }
 
     /**
-     * A helper method to allow lists to work with subscript operators.
+     * Iterates through the given Map, passing in the initial value to
+     * the 2-arg Closure along with the first item (or 3-arg Closure along with the first key and value).
+     * The result is passed back (injected) into
+     * the closure along with the second item. The new result is injected back into
+     * the closure along with the third item and so on until the entire collection
+     * has been used. Also known as <tt>foldLeft</tt> or <tt>reduce</tt> in functional parlance.
+     *
+     * Examples:
      * <pre class="groovyTestCase">
-     * def list = ["a", true]
-     * {@code list[1..<1] = [4, 3, 2]}
-     * assert list == ["a", 4, 3, 2, true]
+     * def map = [a:1, b:2, c:3]
+     * assert map.inject([]) { list, k, v {@code ->}
+     *   list + [k] * v
+     * } == ['a', 'b', 'b', 'c', 'c', 'c']
      * </pre>
      *
-     * @param self  a List
-     * @param range the (in this case empty) subset of the list to set
-     * @param value the Collection of values
-     * @since 1.0
-     * @see #putAt(java.util.List, groovy.lang.EmptyRange, java.lang.Object)
+     * @param self         a Map
+     * @param initialValue some initial value
+     * @param closure      a 2 or 3 arg Closure
+     * @return the result of the last closure call
+     * @since 1.8.1
      */
-    public static void putAt(List self, EmptyRange range, Collection value) {
-        putAt(self, range, (Object)value);
-    }
-
-    private static <T> List<T> resizeListWithRangeAndGetSublist(List<T> self, IntRange range) {
-        RangeInfo info = subListBorders(self.size(), range);
-        int size = self.size();
-        if (info.to >= size) {
-            while (size < info.to) {
-                self.add(size++, null);
+    public static <K, V, T, U extends T, W extends T> T inject(Map<K, V> self, U initialValue, @ClosureParams(value=FromString.class,options={"U,Map.Entry<K,V>","U,K,V"})  Closure<W> closure) {
+        T value = initialValue;
+        for (Map.Entry<K, V> entry : self.entrySet()) {
+            if (closure.getMaximumNumberOfParameters() == 3) {
+                value = closure.call(value, entry.getKey(), entry.getValue());
+            } else {
+                value = closure.call(value, entry);
             }
         }
-        List<T> sublist = self.subList(info.from, info.to);
-        sublist.clear();
-        return sublist;
+        return value;
     }
 
     /**
-     * List subscript assignment operator when given a range as the index and
-     * the assignment operand is a collection.
-     * Example: <pre class="groovyTestCase">def myList = [4, 3, 5, 1, 2, 8, 10]
-     * myList[3..5] = ["a", true]
-     * assert myList == [4, 3, 5, "a", true, 10]</pre>
-     *
-     * Items in the given
-     * range are replaced with items from the collection.
+     * Iterates through the given Iterator, passing in the initial value to
+     * the closure along with the first item. The result is passed back (injected) into
+     * the closure along with the second item. The new result is injected back into
+     * the closure along with the third item and so on until the Iterator has been
+     * expired of values. Also known as foldLeft in functional parlance.
      *
-     * @param self  a List
-     * @param range the subset of the list to set
-     * @param col   the collection of values to put at the given sublist
+     * @param self         an Iterator
+     * @param initialValue some initial value
+     * @param closure      a closure
+     * @return the result of the last closure call
+     * @see #inject(Collection, Object, Closure)
      * @since 1.5.0
      */
-    @SuppressWarnings("unchecked")
-    public static void putAt(List self, IntRange range, Collection col) {
-        List sublist = resizeListWithRangeAndGetSublist(self, range);
-        if (col.isEmpty()) return;
-        sublist.addAll(col);
-    }
-
-    /**
-     * List subscript assignment operator when given a range as the index.
-     * Example: <pre class="groovyTestCase">def myList = [4, 3, 5, 1, 2, 8, 10]
-     * myList[3..5] = "b"
-     * assert myList == [4, 3, 5, "b", 10]</pre>
-     *
-     * Items in the given
-     * range are replaced with the operand.  The <code>value</code> operand is
-     * always treated as a single value.
-     *
-     * @param self  a List
-     * @param range the subset of the list to set
-     * @param value the value to put at the given sublist
-     * @since 1.0
-     */
-    @SuppressWarnings("unchecked")
-    public static void putAt(List self, IntRange range, Object value) {
-        List sublist = resizeListWithRangeAndGetSublist(self, range);
-        sublist.add(value);
+    public static <E,T, U extends T, V extends T> T inject(Iterator<E> self, U initialValue, @ClosureParams(value=FromString.class,options="U,E") Closure<V> closure) {
+        T value = initialValue;
+        Object[] params = new Object[2];
+        while (self.hasNext()) {
+            Object item = self.next();
+            params[0] = value;
+            params[1] = item;
+            value = closure.call(params);
+        }
+        return value;
     }
 
     /**
-     * A helper method to allow lists to work with subscript operators.
-     * <pre class="groovyTestCase">def list = ["a", true, 42, 9.4]
-     * list[1, 4] = ["x", false]
-     * assert list == ["a", "x", 42, 9.4, false]</pre>
+     * Iterates through the given Object, passing in the first value to
+     * the closure along with the first item. The result is passed back (injected) into
+     * the closure along with the second item. The new result is injected back into
+     * the closure along with the third item and so on until further iteration of
+     * the object is not possible. Also known as foldLeft in functional parlance.
      *
-     * @param self   a List
-     * @param splice the subset of the list to set
-     * @param values the value to put at the given sublist
-     * @since 1.0
+     * @param self         an Object
+     * @param closure      a closure
+     * @return the result of the last closure call
+     * @throws NoSuchElementException if the collection is empty.
+     * @see #inject(Collection, Object, Closure)
+     * @since 1.8.7
      */
     @SuppressWarnings("unchecked")
-    public static void putAt(List self, List splice, Collection values) {
-        if (splice.isEmpty()) {
-            if (!values.isEmpty())
-                throw new IllegalArgumentException("Trying to replace 0 elements with " + values.size() + " elements");
-            return;
-        }
-        Object first = splice.iterator().next();
-        if (first instanceof Integer) {
-            if (values.size() != splice.size())
-                throw new IllegalArgumentException("Trying to replace " + splice.size() + " elements with " + values.size() + " elements");
-            Iterator<?> valuesIter = values.iterator();
-            for (Object index : splice) {
-                putAt(self, (Integer) index, valuesIter.next());
-            }
-        } else {
-            throw new IllegalArgumentException("Can only index a List with another List of Integers, not a List of " + first.getClass().getName());
+    public static <T, V extends T> T inject(Object self, Closure<V> closure) {
+        Iterator iter = InvokerHelper.asIterator(self);
+        if( !iter.hasNext() ) {
+            throw new NoSuchElementException( "Cannot call inject() over an empty iterable without passing an initial value." ) ;
         }
+        Object initialValue = iter.next() ;
+        return (T) inject(iter, initialValue, closure);
     }
 
     /**
-     * @deprecated use #putAt(List, List, Collection), retained for binary compatibility
+     * Iterates through the given Object, passing in the initial value to
+     * the closure along with the first item. The result is passed back (injected) into
+     * the closure along with the second item. The new result is injected back into
+     * the closure along with the third item and so on until further iteration of
+     * the object is not possible. Also known as foldLeft in functional parlance.
+     *
+     * @param self         an Object
+     * @param initialValue some initial value
+     * @param closure      a closure
+     * @return the result of the last closure call
+     * @see #inject(Collection, Object, Closure)
+     * @since 1.5.0
      */
-    @Deprecated
     @SuppressWarnings("unchecked")
-    public static void putAt(List self, List splice, List values) {
-        putAt(self, splice, (Collection) values);
+    public static <T, U extends T, V extends T> T inject(Object self, U initialValue, Closure<V> closure) {
+        Iterator iter = InvokerHelper.asIterator(self);
+        return (T) inject(iter, initialValue, closure);
     }
 
     /**
-     * A helper method to allow lists to work with subscript operators.
-     * <pre class="groovyTestCase">def list = ["a", true, 42, 9.4]
-     * list[1, 3] = 5
-     * assert list == ["a", 5, 42, 5]</pre>
+     * Sums the items in an Iterable. This is equivalent to invoking the
+     * "plus" method on all items in the Iterable.
+     * <pre class="groovyTestCase">assert 1+2+3+4 == [1,2,3,4].sum()</pre>
      *
-     * @param self   a List
-     * @param splice the subset of the list to set
-     * @param value  the value to put at the given sublist
-     * @since 1.0
-     */
-    @SuppressWarnings("unchecked")
-    public static void putAt(List self, List splice, Object value) {
-        if (splice.isEmpty()) {
-            return;
-        }
-        Object first = splice.get(0);
-        if (first instanceof Integer) {
-            for (Object index : splice) {
-                self.set((Integer) index, value);
-            }
-        } else {
-            throw new IllegalArgumentException("Can only index a List with another List of Integers, not a List of "+first.getClass().getName());
-        }
+     * @param self Iterable of values to add together
+     * @return The sum of all the items
+     * @see #sum(Iterator)
+     * @since 2.2.0
+     */
+    public static Object sum(Iterable<?> self) {
+        return sum(self.iterator(), null, true);
     }
 
     /**
-     * Support the subscript operator for a Map.
-     * <pre class="groovyTestCase">def map = [1:10]
-     * assert map[1] == 10</pre>
+     * Sums the items from an Iterator. This is equivalent to invoking the
+     * "plus" method on all items from the Iterator. The iterator will become
+     * exhausted of elements after determining the sum value.
      *
-     * @param self a Map
-     * @param key  an Object as a key for the map
-     * @return the value corresponding to the given key
-     * @since 1.0
+     * @param self an Iterator for the values to add together
+     * @return The sum of all the items
+     * @since 1.5.5
      */
-    public static <K,V> V getAt(Map<K,V> self, Object key) {
-        return self.get(key);
+    public static Object sum(Iterator<Object> self) {
+        return sum(self, null, true);
     }
 
     /**
-     * Returns a new <code>Map</code> containing all entries from <code>left</code> and <code>right</code>,
-     * giving precedence to <code>right</code>.  Any keys appearing in both Maps
-     * will appear in the resultant map with values from the <code>right</code>
-     * operand. If the <code>left</code> map is one of TreeMap, LinkedHashMap, Hashtable
-     * or Properties, the returned Map will preserve that type, otherwise a HashMap will
-     * be returned.
-     * <p>
-     * Roughly equivalent to <code>Map m = new HashMap(); m.putAll(left); m.putAll(right); return m;</code>
-     * but with some additional logic to preserve the <code>left</code> Map type for common cases as
-     * described above.
+     * Sums the items in an Iterable, adding the result to some initial value.
      * <pre class="groovyTestCase">
-     * assert [a:10, b:20] + [a:5, c:7] == [a:5, b:20, c:7]
+     * assert 5+1+2+3+4 == [1,2,3,4].sum(5)
      * </pre>
      *
-     * @param left  a Map
-     * @param right a Map
-     * @return a new Map containing all entries from left and right
-     * @since 1.5.0
+     * @param self         an Iterable of values to sum
+     * @param initialValue the items in the collection will be summed to this initial value
+     * @return The sum of all the items.
+     * @see #sum(Iterator, Object)
+     * @since 2.2.0
      */
-    public static <K, V> Map<K, V> plus(Map<K, V> left, Map<K, V> right) {
-        Map<K, V> map = cloneSimilarMap(left);
-        map.putAll(right);
-        return map;
+    public static Object sum(Iterable<?> self, Object initialValue) {
+        return sum(self.iterator(), initialValue, false);
     }
 
     /**
-     * A helper method to allow maps to work with subscript operators
+     * Sums the items from an Iterator, adding the result to some initial value. This is
+     * equivalent to invoking the "plus" method on all items from the Iterator. The iterator
+     * will become exhausted of elements after determining the sum value.
      *
-     * @param self  a Map
-     * @param key   an Object as a key for the map
-     * @param value the value to put into the map
-     * @return the value corresponding to the given key
-     * @since 1.0
+     * @param self         an Iterator for the values to add together
+     * @param initialValue the items in the collection will be summed to this initial value
+     * @return The sum of all the items
+     * @since 1.5.5
      */
-    public static <K,V> V putAt(Map<K,V> self, K key, V value) {
-        self.put(key, value);
-        return value;
+    public static Object sum(Iterator<?> self, Object initialValue) {
+        return sum(self, initialValue, false);
+    }
+
+    static Object sum(Iterator<?> self, Object initialValue, boolean first) {
+        Object result = initialValue;
+        Object[] param = new Object[1];
+        while (self.hasNext()) {
+            Object next = self.next();
+            param[0] = next;
+            if (first) {
+                result = param[0];
+                first = false;
+                continue;
+            }
+            MetaClass metaClass = InvokerHelper.getMetaClass(result);
+            result = metaClass.invokeMethod(result, "plus", param);
+        }
+        return result;
     }
 
     /**
-     * Support the subscript operator for Collection.
-     * <pre class="groovyTestCase">
-     * assert [String, Long, Integer] == ["a",5L,2]["class"]
-     * </pre>
+     * Sums the result of applying a closure to each item of an Iterable.
+     * <code>coll.sum(closure)</code> is equivalent to:
+     * <code>coll.collect(closure).sum()</code>.
+     * <pre class="groovyTestCase">assert 4+6+10+12 == [2,3,5,6].sum { it * 2 }</pre>
      *
-     * @param coll     a Collection
-     * @param property a String
-     * @return a List
-     * @since 1.0
+     * @param self    an Iterable
+     * @param closure a single parameter closure that returns a (typically) numeric value.
+     * @return The sum of the values returned by applying the closure to each
+     *         item of the Iterable.
+     * @since 2.2.0
      */
-    public static List getAt(Collection coll, String property) {
-        List<Object> answer = new ArrayList<>(coll.size());
-        return getAtIterable(coll, property, answer);
+    public static <T> Object sum(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return sum(self.iterator(), null, closure, true);
     }
 
-    private static List getAtIterable(Iterable coll, String property, List<Object> answer) {
-        for (Object item : coll) {
-            if (item == null) continue;
-            Object value;
-            try {
-                value = InvokerHelper.getProperty(item, property);
-            } catch (MissingPropertyExceptionNoStack mpe) {
-                String causeString = new MissingPropertyException(mpe.getProperty(), mpe.getType()).toString();
-                throw new MissingPropertyException("Exception evaluating property '" + property +
-                        "' for " + coll.getClass().getName() + ", Reason: " + causeString);
-            }
-            answer.add(value);
-        }
-        return answer;
+    /**
+     * Sums the result of applying a closure to each item returned from an iterator.
+     * <code>iter.sum(closure)</code> is equivalent to:
+     * <code>iter.collect(closure).sum()</code>. The iterator will become
+     * exhausted of elements after determining the sum value.
+     *
+     * @param self    An Iterator
+     * @param closure a single parameter closure that returns a (typically) numeric value.
+     * @return The sum of the values returned by applying the closure to each
+     *         item from the Iterator.
+     * @since 1.7.1
+     */
+    public static <T> Object sum(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return sum(self, null, closure, true);
     }
 
     /**
-     * Synonym for {@link #toSpreadMap(java.util.Map)}.
+     * Sums the result of applying a closure to each item of an Iterable to some initial value.
+     * <code>iter.sum(initVal, closure)</code> is equivalent to:
+     * <code>iter.collect(closure).sum(initVal)</code>.
+     * <pre class="groovyTestCase">assert 50+4+6+10+12 == [2,3,5,6].sum(50) { it * 2 }</pre>
      *
-     * @param self a map
-     * @return a newly created SpreadMap
-     * @since 1.0
+     * @param self         an Iterable
+     * @param closure      a single parameter closure that returns a (typically) numeric value.
+     * @param initialValue the closure results will be summed to this initial value
+     * @return The sum of the values returned by applying the closure to each
+     *         item of the collection.
+     * @since 1.5.0
      */
-    public static SpreadMap spread(Map self) {
-        return toSpreadMap(self);
+    public static <T> Object sum(Iterable<T> self, Object initialValue, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return sum(self.iterator(), initialValue, closure, false);
     }
 
     /**
-     * Returns a new <code>SpreadMap</code> from this map.
-     * <p>
-     * The example below shows the various possible use cases:
-     * <pre class="groovyTestCase">
-     * def fn(Map m) { return m.a + m.b + m.c + m.d }
-     *
-     * assert fn(a:1, b:2, c:3, d:4) == 10
-     * assert fn(a:1, *:[b:2, c:3], d:4) == 10
-     * assert fn([a:1, b:2, c:3, d:4].toSpreadMap()) == 10
-     * assert fn((['a', 1, 'b', 2, 'c', 3, 'd', 4] as Object[]).toSpreadMap()) == 10
-     * assert fn(['a', 1, 'b', 2, 'c', 3, 'd', 4].toSpreadMap()) == 10
-     * assert fn(['abcd'.toList(), 1..4].transpose().flatten().toSpreadMap()) == 10
-     * </pre>
-     * Note that toSpreadMap() is not normally used explicitly but under the covers by Groovy.
+     * Sums the result of applying a closure to each item of an Iterator to some initial value.
+     * <code>iter.sum(initVal, closure)</code> is equivalent to:
+     * <code>iter.collect(closure).sum(initVal)</code>. The iterator will become
+     * exhausted of elements after determining the sum value.
      *
-     * @param self a map to be converted into a SpreadMap
-     * @return a newly created SpreadMap if this map is not null and its size is positive.
-     * @see groovy.lang.SpreadMap#SpreadMap(java.util.Map)
-     * @since 1.0
+     * @param self         an Iterator
+     * @param closure      a single parameter closure that returns a (typically) numeric value.
+     * @param initialValue the closure results will be summed to this initial value
+     * @return The sum of the values returned by applying the closure to each
+     *         item from the Iterator.
+     * @since 1.7.1
      */
-    public static SpreadMap toSpreadMap(Map self) {
-        if (self == null)
-            throw new GroovyRuntimeException("Fail to convert Map to SpreadMap, because it is null.");
-        else
-            return new SpreadMap(self);
+    public static <T> Object sum(Iterator<T> self, Object initialValue, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return sum(self, initialValue, closure, false);
+    }
+
+    static Object sum(Iterator<?> self, Object initialValue, Closure closure, boolean first) {
+        Object result = initialValue;
+        Object[] closureParam = new Object[1];
+        Object[] plusParam = new Object[1];
+        while (self.hasNext()) {
+            closureParam[0] = self.next();
+            plusParam[0] = closure.call(closureParam);
+            if (first) {
+                result = plusParam[0];
+                first = false;
+                continue;
+            }
+            MetaClass metaClass = InvokerHelper.getMetaClass(result);
+            result = metaClass.invokeMethod(result, "plus", plusParam);
+        }
+        return result;
     }
 
     /**
-     * Creates a spreadable map from this list.
-     * <p>
-     * @param self a list
-     * @return a newly created SpreadMap
-     * @see groovy.lang.SpreadMap#SpreadMap(java.util.List)
-     * @see #toSpreadMap(java.util.Map)
-     * @since 1.8.0
+     * Concatenates the <code>toString()</code> representation of each item from
+     * the Iterator, with the given String as a separator between each item. The
+     * iterator will become exhausted of elements after producing the resulting
+     * conjoined value.
+     *
+     * @param self      an Iterator of objects
+     * @param separator a String separator
+     * @return the joined String
+     * @since 1.5.5
      */
-    public static SpreadMap toSpreadMap(List self) {
-        if (self == null)
-            throw new GroovyRuntimeException("Fail to convert List to SpreadMap, because it is null.");
-        else if (self.size() % 2 != 0)
-            throw new GroovyRuntimeException("Fail to convert List to SpreadMap, because its size is not even.");
-        else
-            return new SpreadMap(self);
+    public static String join(final Iterator<?> self, final String separator) {
+        StringJoiner joiner = new StringJoiner(separator != null ? separator : "");
+        while (self.hasNext()) {
+            Object obj = self.next();
+            String str = FormatHelper.toString(obj);
+            joiner.add(str);
+        }
+        return joiner.toString();
     }
 
     /**
-     * Creates a spreadable map from this iterable.
+     * Concatenates the <code>toString()</code> representation of each item from
+     * the Iterable, with the given String as a separator between each item.
      * <p>
-     * @param self an iterable
-     * @return a newly created SpreadMap
-     * @see groovy.lang.SpreadMap#SpreadMap(java.util.List)
-     * @see #toSpreadMap(java.util.Map)
-     * @since 2.4.0
-     */
-    @SuppressWarnings("unchecked")
-    public static SpreadMap toSpreadMap(Iterable self) {
-        if (self == null)
-            throw new GroovyRuntimeException("Fail to convert Iterable to SpreadMap, because it is null.");
-        else
-            return toSpreadMap(asList(self));
+     * <pre class="groovyTestCase">assert [1,2,3].join() == "123"</pre>
+     * <pre class="groovyTestCase">assert [1,2,3].join(", ") == "1, 2, 3"</pre>
+     *
+     * @param self      an Iterable of objects
+     * @param separator a String separator
+     * @return the joined String
+     * @since 1.0
+     */
+    public static String join(final Iterable<?> self, final String separator) {
+        return join(self.iterator(), separator);
     }
 
     /**
-     * Wraps a map using the decorator pattern with a wrapper that intercepts all calls
-     * to <code>get(key)</code>. If an unknown key is found, a default value will be
-     * stored into the Map before being returned. The default value stored will be the
-     * result of calling the supplied Closure with the key as the parameter to the Closure.
-     *
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * def map = [a:1, b:2].withDefault{ k {@code ->} k.toCharacter().isLowerCase() ? 10 : -10 }
-     * def expected = [a:1, b:2, c:10, D:-10]
-     * assert expected.every{ e {@code ->} e.value == map[e.key] }
-     *
-     * def constMap = [:].withDefault{ 42 }
-     * assert constMap.foo == 42
-     * assert constMap.size() == 1
-     * </pre>
+     * Adds min() method to Collection objects.
+     * <pre class="groovyTestCase">assert 2 == [4,2,5].min()</pre>
      *
-     * @param self a Map
-     * @param init a Closure which is passed the unknown key
-     * @return the wrapped Map
-     * @since 1.7.1
-     * @see #withDefault(Map, boolean, boolean, Closure)
+     * @param self a Collection
+     * @return the minimum value
+     * @see #min(Iterator)
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> withDefault(Map<K, V> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> init) {
-        return MapWithDefault.newInstance(self, true, false, init);
+    public static <T> T min(Iterable<T> self) {
+        return min(self.iterator());
     }
 
     /**
-     * Wraps a map using the decorator pattern with a wrapper that intercepts all calls
-     * to <code>get(key)</code> and <code>put(key, value)</code>.
-     * If an unknown key is found for <code>get</code>, a default value will be returned.
-     * The default value will be the result of calling the supplied Closure with the key
-     * as the parameter to the Closure.
-     * If <code>autoGrow</code> is set, the value will be stored into the map.
-     *
-     * If <code>autoShrink</code> is set, then an attempt to <code>put</code> the default value
-     * into the map is ignored and indeed any existing value would be removed.
-     *
-     * If you wish the backing map to be as small as possible, consider setting <code>autoGrow</code>
-     * to <code>false</code> and <code>autoShrink</code> to <code>true</code>.
-     * This keeps the backing map as small as possible, i.e. sparse, but also means that
-     * <code>containsKey</code>, <code>keySet</code>, <code>size</code>, and other methods
-     * will only reflect the sparse values.
-     *
-     * If you are wrapping an immutable map, you should set <code>autoGrow</code>
-     * and <code>autoShrink</code> to <code>false</code>.
-     * In this scenario, the <code>get</code> method is essentially a shorthand
-     * for calling <code>getOrDefault</code> with the default value supplied once as a Closure.
-     *
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * // sparse map example
-     * def answers = [life: 100].withDefault(false, true){ 42 }
-     * assert answers.size() == 1
-     * assert answers.foo == 42
-     * assert answers.size() == 1
-     * answers.life = 42
-     * answers.putAll(universe: 42, everything: 42)
-     * assert answers.size() == 0
-     *
-     * // immutable map example
-     * def certainties = [death: true, taxes: true].asImmutable().withDefault(false, false){ false }
-     * assert certainties.size() == 2
-     * assert certainties.wealth == false
-     * assert certainties.size() == 2
-     * </pre>
+     * Adds min() method to Iterator objects. The iterator will become
+     * exhausted of elements after determining the minimum value.
      *
-     * @param self a Map
-     * @param autoGrow whether calling get could potentially grow the map if the key isn't found
-     * @param autoShrink whether calling put with the default value could potentially shrink the map
-     * @param init a Closure which is passed the unknown key
-     * @return the wrapped Map
-     * @since 4.0.1
+     * @param self an Iterator
+     * @return the minimum value
+     * @see #min(Iterable)
+     * @since 1.5.5
      */
-    public static <K, V> Map<K, V> withDefault(Map<K, V> self, boolean autoGrow, boolean autoShrink, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> init) {
-        return MapWithDefault.newInstance(self, autoGrow, autoShrink, init);
+    public static <T> T min(Iterator<T> self) {
+        T answer = null;
+        while (self.hasNext()) {
+            T value =  self.next();
+            if (value != null && (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer))) {
+                answer = value;
+            }
+        }
+        return answer;
     }
 
     /**
-     * An alias for <code>withLazyDefault</code> which decorates a list allowing
-     * it to grow when called with index values outside the normal list bounds.
+     * Selects the minimum value found in the Iterable using the given comparator.
+     * <pre class="groovyTestCase">assert "hi" == ["hello","hi","hey"].min( { a, b {@code ->} a.length() {@code <=>} b.length() } as Comparator )</pre>
      *
-     * @param self a List
-     * @param init a Closure with the target index as parameter which generates the default value
-     * @return the decorated List
-     * @see #withLazyDefault(java.util.List, groovy.lang.Closure)
-     * @see #withEagerDefault(java.util.List, groovy.lang.Closure)
-     * @since 1.8.7
+     * @param self       an Iterable
+     * @param comparator a Comparator
+     * @return the minimum value or null for an empty Iterable
+     * @see #min(Iterator, java.util.Comparator)
+     * @since 2.2.0
      */
-    public static <T> ListWithDefault<T> withDefault(List<T> self, @ClosureParams(value=SimpleType.class, options = "int") Closure<T> init) {
-        return withLazyDefault(self, init);
+    public static <T> T min(Iterable<T> self, Comparator<? super T> comparator) {
+        return min(self.iterator(), comparator);
     }
 
     /**
-     * Decorates a list allowing it to grow when called with a non-existent index value.
-     * When called with such values, the list is grown in size and a default value
-     * is placed in the list by calling a supplied <code>init</code> Closure. Subsequent
-     * retrieval operations if finding a null value in the list assume it was set
-     * as null from an earlier growing operation and again call the <code>init</code> Closure
-     * to populate the retrieved value; consequently the list can't be used to store null values.
-     * <p>
-     * How it works: The decorated list intercepts all calls
-     * to <code>getAt(index)</code> and <code>get(index)</code>. If an index greater than
-     * or equal to the current <code>size()</code> is used, the list will grow automatically
-     * up to the specified index. Gaps will be filled by {@code null}. If a default value
-     * should also be used to fill gaps instead of {@code null}, use <code>withEagerDefault</code>.
-     * If <code>getAt(index)</code> or <code>get(index)</code> are called and a null value
-     * is found, it is assumed that the null value was a consequence of an earlier grow list
-     * operation and the <code>init</code> Closure is called to populate the value.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * def list = [0, 1].withLazyDefault{ 42 }
-     * assert list[0] == 0
-     * assert list[1] == 1
-     * assert list[3] == 42   // default value
-     * assert list == [0, 1, null, 42] // gap filled with null
-     *
-     * // illustrate using the index when generating default values
-     * def list2 = [5].withLazyDefault{ index {@code ->} index * index }
-     * assert list2[3] == 9
-     * assert list2 == [5, null, null, 9]
-     * assert list2[2] == 4
-     * assert list2 == [5, null, 4, 9]
-     *
-     * // illustrate what happens with null values
-     * list2[2] = null
-     * assert list2[2] == 4
-     * </pre>
+     * Selects the minimum value found from the Iterator using the given comparator.
      *
-     * @param self a List
-     * @param init a Closure with the target index as parameter which generates the default value
-     * @return the decorated List
-     * @since 1.8.7
+     * @param self       an Iterator
+     * @param comparator a Comparator
+     * @return the minimum value
+     * @since 1.5.5
      */
-    public static <T> ListWithDefault<T> withLazyDefault(List<T> self, @ClosureParams(value=SimpleType.class, options="int") Closure<T> init) {
-        return ListWithDefault.newInstance(self, true, init);
+    public static <T> T min(Iterator<T> self, Comparator<? super T> comparator) {
+        Objects.requireNonNull(self);
+        T answer = null;
+        boolean first = true;
+        while (self.hasNext()) {
+            T value = self.next();
+            if (first) {
+                first = false;
+                answer = value;
+            } else if (comparator.compare(value, answer) < 0) {
+                answer = value;
+            }
+        }
+        return answer;
     }
 
     /**
-     * Decorates a list allowing it to grow when called with a non-existent index value.
-     * When called with such values, the list is grown in size and a default value
-     * is placed in the list by calling a supplied <code>init</code> Closure. Null values
-     * can be stored in the list.
-     * <p>
-     * How it works: The decorated list intercepts all calls
-     * to <code>getAt(index)</code> and <code>get(index)</code>. If an index greater than
-     * or equal to the current <code>size()</code> is used, the list will grow automatically
-     * up to the specified index. Gaps will be filled by calling the <code>init</code> Closure.
-     * If generating a default value is a costly operation consider using <code>withLazyDefault</code>.
+     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
+     * minimum value. A null return value represents the least possible return value. If more than one item
+     * has the minimum value, an arbitrary choice is made between the items having the minimum value.
      * <p>
-     * Example usage:
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
      * <pre class="groovyTestCase">
-     * def list = [0, 1].withEagerDefault{ 42 }
-     * assert list[0] == 0
-     * assert list[1] == 1
-     * assert list[3] == 42   // default value
-     * assert list == [0, 1, 42, 42]   // gap filled with default value
-     *
-     * // illustrate using the index when generating default values
-     * def list2 = [5].withEagerDefault{ index {@code ->} index * index }
-     * assert list2[3] == 9
-     * assert list2 == [5, 1, 4, 9]
-     *
-     * // illustrate what happens with null values
-     * list2[2] = null
-     * assert list2[2] == null
-     * assert list2 == [5, 1, null, 9]
+     * assert "hi" == ["hello","hi","hey"].min { it.length() }
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def lastDigit = { a, b {@code ->} a % 10 {@code <=>} b % 10 }
+     * assert [19, 55, 91].min(lastDigit) == 91
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def pets = ['dog', 'cat', 'anaconda']
+     * def shortestName = pets.min{ it.size() } // one of 'dog' or 'cat'
+     * assert shortestName.size() == 3
      * </pre>
      *
-     * @param self a List
-     * @param init a Closure with the target index as parameter which generates the default value
-     * @return the wrapped List
-     * @since 1.8.7
+     * @param self    an Iterable
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return an item from the Iterable having the minimum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
+     * @see #min(Iterator)
+     * @since 1.0
      */
-    public static <T> ListWithDefault<T> withEagerDefault(List<T> self, @ClosureParams(value=SimpleType.class, options="int") Closure<T> init) {
-        return ListWithDefault.newInstance(self, false, init);
+    public static <T> T min(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return min(self.iterator(), closure);
     }
 
     /**
-     * Zips an Iterable with indices in (value, index) order.
-     * <p/>
-     * Example usage:
+     * Selects an entry in the map having the minimum
+     * calculated value as determined by the supplied closure.
+     * If more than one entry has the minimum value,
+     * an arbitrary choice is made between the entries having the minimum value.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
+     * <pre class="groovyTestCase">
+     * def zoo = [monkeys:6, lions:5, tigers:7]
+     * def leastCommonEntry = zoo.min{ it.value }
+     * assert leastCommonEntry.value == 5
+     * def mostCommonEntry = zoo.min{ a, b {@code ->} b.value {@code <=>} a.value } // double negative!
+     * assert mostCommonEntry.value == 7
+     * </pre>
+     * Edge case for multiple min values:
      * <pre class="groovyTestCase">
-     * assert [["a", 0], ["b", 1]] == ["a", "b"].withIndex()
-     * assert ["0: a", "1: b"] == ["a", "b"].withIndex().collect { str, idx {@code ->} "$idx: $str" }
+     * def zoo = [monkeys:6, lions:5, tigers:7]
+     * def lastCharOfName = { e {@code ->} e.key[-1] }
+     * def ans = zoo.min(lastCharOfName) // some random entry
+     * assert lastCharOfName(ans) == 's'
      * </pre>
      *
-     * @param self an Iterable
-     * @return a zipped list with indices
-     * @see #indexed(Iterable)
-     * @since 2.4.0
+     * @param self    a Map
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return the Map.Entry having the minimum value as determined by the closure
+     * @since 1.7.6
      */
-    public static <E> List<Tuple2<E, Integer>> withIndex(Iterable<E> self) {
-        return withIndex(self, 0);
+    public static <K, V> Map.Entry<K, V> min(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>", "Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
+        return min(self.entrySet(), closure);
     }
 
     /**
-     * Zips an Iterable with indices in (index, value) order.
-     * <p/>
-     * Example usage:
+     * Selects an entry in the map having the maximum
+     * calculated value as determined by the supplied closure.
+     * If more than one entry has the maximum value,
+     * an arbitrary choice is made between the entries having the maximum value.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison. An example:
      * <pre class="groovyTestCase">
-     * assert [0: "a", 1: "b"] == ["a", "b"].indexed()
-     * assert ["0: a", "1: b"] == ["a", "b"].indexed().collect { idx, str {@code ->} "$idx: $str" }
+     * def zoo = [monkeys:6, lions:5, tigers:7]
+     * def mostCommonEntry = zoo.max{ it.value }
+     * assert mostCommonEntry.value == 7
+     * def leastCommonEntry = zoo.max{ a, b {@code ->} b.value {@code <=>} a.value } // double negative!
+     * assert leastCommonEntry.value == 5
+     * </pre>
+     * Edge case for multiple max values:
+     * <pre class="groovyTestCase">
+     * def zoo = [monkeys:6, lions:5, tigers:7]
+     * def lengthOfNamePlusNumber = { e {@code ->} e.key.size() + e.value }
+     * def ans = zoo.max(lengthOfNamePlusNumber) // one of [monkeys:6, tigers:7]
+     * assert lengthOfNamePlusNumber(ans) == 13
      * </pre>
      *
-     * @param self an Iterable
-     * @return a zipped map with indices
-     * @see #withIndex(Iterable)
-     * @since 2.4.0
+     * @param self    a Map
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return the Map.Entry having the maximum value as determined by the closure
+     * @since 1.7.6
      */
-    public static <E> Map<Integer, E> indexed(Iterable<E> self) {
-        return indexed(self, 0);
+    public static <K, V> Map.Entry<K, V> max(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>", "Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
+        return max(self.entrySet(), closure);
     }
 
     /**
-     * Zips an Iterable with indices in (value, index) order.
-     * <p/>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * assert [["a", 5], ["b", 6]] == ["a", "b"].withIndex(5)
-     * assert ["1: a", "2: b"] == ["a", "b"].withIndex(1).collect { str, idx {@code ->} "$idx: $str" }
-     * </pre>
+     * Selects the minimum value found from the Iterator
+     * using the closure to determine the correct ordering.
+     * The iterator will become
+     * exhausted of elements after this operation.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
      *
-     * @param self   an Iterable
-     * @param offset an index to start from
-     * @return a zipped list with indices
-     * @see #indexed(Iterable, int)
-     * @since 2.4.0
+     * @param self    an Iterator
+     * @param closure a Closure used to determine the correct ordering
+     * @return the minimum value
+     * @since 1.5.5
      */
-    public static <E> List<Tuple2<E, Integer>> withIndex(Iterable<E> self, int offset) {
-        return toList(withIndex(self.iterator(), offset));
+    public static <T> T min(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        int params = closure.getMaximumNumberOfParameters();
+        if (params != 1) {
+            return min(self, new ClosureComparator<>(closure));
+        }
+        Objects.requireNonNull(self);
+        boolean first = true;
+        T answer = null;
+        Object answerValue = null;
+        while (self.hasNext()) {
+            T item = self.next();
+            Object value = closure.call(item);
+            if (first) {
+                first = false;
+                answer = item;
+                answerValue = value;
+            } else if (ScriptBytecodeAdapter.compareLessThan(value, answerValue)) {
+                answer = item;
+                answerValue = value;
+            }
+        }
+        return answer;
     }
 
     /**
-     * Zips an Iterable with indices in (index, value) order.
-     * <p/>
-     * Example usage:
+     * Adds max() method to Iterable objects.
      * <pre class="groovyTestCase">
-     * assert [5: "a", 6: "b"] == ["a", "b"].indexed(5)
-     * assert ["1: a", "2: b"] == ["a", "b"].indexed(1).collect { idx, str {@code ->} "$idx: $str" }
+     * assert 5 == [2,3,1,5,4].max()
      * </pre>
      *
-     * @param self   an Iterable
-     * @param offset an index to start from
-     * @return a Map (since the keys/indices are unique) containing the elements from the iterable zipped with indices
-     * @see #withIndex(Iterable, int)
-     * @since 2.4.0
+     * @param self an Iterable
+     * @return the maximum value
+     * @see #max(Iterator)
+     * @since 2.2.0
      */
-    public static <E> Map<Integer, E> indexed(Iterable<E> self, int offset) {
-        Objects.requireNonNull(self);
-        Map<Integer, E> result = new LinkedHashMap<>();
-        Iterator<Tuple2<Integer, E>> indexed = indexed(self.iterator(), offset);
-        while (indexed.hasNext()) {
-            Tuple2<Integer, E> next = indexed.next();
-            result.put(next.getV1(), next.getV2());
-        }
-        return result;
+    public static <T> T max(Iterable<T> self) {
+        return max(self.iterator());
     }
 
     /**
-     * Zips an iterator with indices in (value, index) order.
-     * <p/>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * assert [["a", 0], ["b", 1]] == ["a", "b"].iterator().withIndex().toList()
-     * assert ["0: a", "1: b"] == ["a", "b"].iterator().withIndex().collect { str, idx {@code ->} "$idx: $str" }.toList()
-     * </pre>
+     * Adds max() method to Iterator objects. The iterator will become
+     * exhausted of elements after determining the maximum value.
      *
-     * @param self an iterator
-     * @return a zipped iterator with indices
-     * @see #indexed(Iterator)
-     * @since 2.4.0
+     * @param self an Iterator
+     * @return the maximum value
+     * @since 1.5.5
      */
-    public static <E> Iterator<Tuple2<E, Integer>> withIndex(Iterator<E> self) {
-        return withIndex(self, 0);
+    public static <T> T max(Iterator<T> self) {
+        T answer = null;
+        while (self.hasNext()) {
+            T value =  self.next();
+            if (value != null && (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer))) {
+                answer = value;
+            }
+        }
+        return answer;
     }
 
     /**
-     * Zips an iterator with indices in (index, value) order.
-     * <p/>
-     * Example usage:
+     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
+     * maximum value. A null return value represents the least possible return value, so any item for which
+     * the supplied closure returns null, won't be selected (unless all items return null). If more than one item
+     * has the maximum value, an arbitrary choice is made between the items having the maximum value.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
+     * <pre class="groovyTestCase">assert "hello" == ["hello","hi","hey"].max { it.length() }</pre>
+     * <pre class="groovyTestCase">assert "hello" == ["hello","hi","hey"].max { a, b {@code ->} a.length() {@code <=>} b.length() }</pre>
      * <pre class="groovyTestCase">
-     * assert [[0, "a"], [1, "b"]] == ["a", "b"].iterator().indexed().collect{ tuple {@code ->} [tuple.first, tuple.second] }
-     * assert ["0: a", "1: b"] == ["a", "b"].iterator().indexed().collect { idx, str {@code ->} "$idx: $str" }.toList()
+     * def pets = ['dog', 'elephant', 'anaconda']
+     * def longestName = pets.max{ it.size() } // one of 'elephant' or 'anaconda'
+     * assert longestName.size() == 8
      * </pre>
      *
-     * @param self an iterator
-     * @return a zipped iterator with indices
-     * @see #withIndex(Iterator)
-     * @since 2.4.0
+     * @param self    an Iterable
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return an item from the Iterable having the maximum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
+     * @since 2.2.0
      */
-    public static <E> Iterator<Tuple2<Integer, E>> indexed(Iterator<E> self) {
-        return indexed(self, 0);
+    public static <T> T max(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return max(self.iterator(), closure);
     }
 
     /**
-     * Zips an iterator with indices in (value, index) order.
-     * <p/>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * assert [["a", 5], ["b", 6]] == ["a", "b"].iterator().withIndex(5).toList()
-     * assert ["1: a", "2: b"] == ["a", "b"].iterator().withIndex(1).collect { str, idx {@code ->} "$idx: $str" }.toList()
-     * </pre>
+     * Selects the maximum value found from the Iterator
+     * using the closure to determine the correct ordering.
+     * The iterator will become exhausted of elements after this operation.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
      *
-     * @param self   an iterator
-     * @param offset an index to start from
-     * @return a zipped iterator with indices
-     * @see #indexed(Iterator, int)
-     * @since 2.4.0
+     * @param self    an Iterator
+     * @param closure a Closure used to determine the correct ordering
+     * @return the maximum value
+     * @since 1.5.5
      */
-    public static <E> Iterator<Tuple2<E, Integer>> withIndex(Iterator<E> self, int offset) {
-        return new ZipPostIterator<>(self, offset);
+    public static <T> T max(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        int params = closure.getMaximumNumberOfParameters();
+        if (params != 1) {
+            return max(self, new ClosureComparator<>(closure));
+        }
+        boolean first = true;
+        T answer = null;
+        Object answerValue = null;
+        while (self.hasNext()) {
+            T item = self.next();
+            Object value = closure.call(item);
+            if (first) {
+                first = false;
+                answer = item;
+                answerValue = value;
+            } else if (ScriptBytecodeAdapter.compareLessThan(answerValue, value)) {
+                answer = item;
+                answerValue = value;
+            }
+        }
+        return answer;
     }
 
     /**
-     * Zips an iterator with indices in (index, value) order.
-     * <p/>
-     * Example usage:
+     * Selects the maximum value found in the Iterable using the given comparator.
      * <pre class="groovyTestCase">
-     * assert [[5, "a"], [6, "b"]] == ["a", "b"].iterator().indexed(5).toList()
-     * assert ["a: 1", "b: 2"] == ["a", "b"].iterator().indexed(1).collect { idx, str {@code ->} "$str: $idx" }.toList()
+     * assert "hello" == ["hello","hi","hey"].max( { a, b {@code ->} a.length() {@code <=>} b.length() } as Comparator )
      * </pre>
      *
-     * @param self   an iterator
-     * @param offset an index to start from
-     * @return a zipped iterator with indices
-     * @see #withIndex(Iterator, int)
-     * @since 2.4.0
+     * @param self       an Iterable
+     * @param comparator a Comparator
+     * @return the maximum value or null for an empty Iterable
+     * @see #max(Iterator, Comparator)
+     * @since 2.2.0
      */
-    public static <E> Iterator<Tuple2<Integer, E>> indexed(Iterator<E> self, int offset) {
-        return new ZipPreIterator<>(self, offset);
+    public static <T> T max(Iterable<T> self, Comparator<? super T> comparator) {
+        return max(self.iterator(), comparator);
     }
 
-    private static final class ZipPostIterator<E> implements Iterator<Tuple2<E, Integer>> {
-        private final Iterator<E> delegate;
-        private int index;
-
-        private ZipPostIterator(Iterator<E> delegate, int offset) {
-            this.delegate = delegate;
-            this.index = offset;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return delegate.hasNext();
-        }
-
-        @Override
-        public Tuple2<E, Integer> next() {
-            if (!hasNext()) throw new NoSuchElementException();
-            return new Tuple2<>(delegate.next(), index++);
-        }
-
-        @Override
-        public void remove() {
-            delegate.remove();
+    /**
+     * Selects the maximum value found from the Iterator using the given comparator.
+     *
+     * @param self       an Iterator
+     * @param comparator a Comparator
+     * @return the maximum value
+     * @since 1.5.5
+     */
+    public static <T> T max(Iterator<T> self, Comparator<? super T> comparator) {
+        T answer = null;
+        while (self.hasNext()) {
+            T value = self.next();
+            if (value != null && (answer == null || comparator.compare(value, answer) > 0)) {
+                answer = value;
+            }
         }
+        return answer;
     }
 
-    private static final class ZipPreIterator<E> implements Iterator<Tuple2<Integer, E>> {
-        private final Iterator<E> delegate;
-        private int index;
-
-        private ZipPreIterator(Iterator<E> delegate, int offset) {
-            this.delegate = delegate;
-            this.index = offset;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return delegate.hasNext();
-        }
-
-        @Override
-        public Tuple2<Integer, E> next() {
-            if (!hasNext()) throw new NoSuchElementException();
-            return new Tuple2<>(index++, delegate.next());
-        }
-
-        @Override
-        public void remove() {
-            delegate.remove();
+    /**
+     * Provide the standard Groovy <code>size()</code> method for <code>Iterator</code>.
+     * The iterator will become exhausted of elements after determining the size value.
+     *
+     * @param self an Iterator
+     * @return the length of the Iterator
+     * @since 1.5.5
+     */
+    public static int size(Iterator self) {
+        int count = 0;
+        while (self.hasNext()) {
+            self.next();
+            count++;
         }
+        return count;
     }
 
     /**
-     * Sorts the Collection. Assumes that the collection items are comparable
-     * and uses their natural ordering to determine the resulting order.
-     * If the Collection is a List, it is sorted in place and returned.
-     * Otherwise, the elements are first placed into a new list which is then
-     * sorted and returned - leaving the original Collection unchanged.
-     * <pre class="groovyTestCase">assert [1,2,3] == [3,1,2].sort()</pre>
+     * Provide the standard Groovy <code>size()</code> method for <code>Iterable</code>.
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 3]
+     * def iterable = { [ hasNext:{ !items.isEmpty() }, next:{ items.pop() } ] as Iterator } as Iterable
+     * assert iterable.size() == 3
+     * </pre>
      *
-     * @param self the Iterable to be sorted
-     * @return the sorted Iterable as a List
-     * @see #sort(Iterable, boolean)
-     * @since 2.2.0
+     * @param self an Iterable
+     * @return the length of the Iterable
+     * @since 2.3.8
      */
-    public static <T> List<T> sort(Iterable<T> self) {
-        return sort(self, true);
+    public static int size(Iterable self) {
+        return size(self.iterator());
     }
 
     /**
-     * Sorts the Iterable. Assumes that the Iterable items are
-     * comparable and uses their natural ordering to determine the resulting order.
-     * If the Iterable is a List and mutate is true,
-     * it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <pre class="groovyTestCase">assert [1,2,3] == [3,1,2].sort()</pre>
+     * Check whether an <code>Iterable</code> has elements
      * <pre class="groovyTestCase">
-     * def orig = [1, 3, 2]
-     * def sorted = orig.sort(false)
-     * assert orig == [1, 3, 2]
-     * assert sorted == [1, 2, 3]
+     * def items = [1]
+     * def iterable = { [ hasNext:{ !items.isEmpty() }, next:{ items.pop() } ] as Iterator } as Iterable
+     * assert !iterable.isEmpty()
+     * iterable.iterator().next()
+     * assert iterable.isEmpty()
      * </pre>
      *
-     * @param self   the iterable to be sorted
-     * @param mutate false will always cause a new list to be created, true will mutate lists in place
-     * @return the sorted iterable as a List
-     * @since 2.2.0
+     * @param self an Iterable
+     * @return true if the iterable has no elements, false otherwise
+     * @since 2.5.0
      */
-    public static <T> List<T> sort(Iterable<T> self, boolean mutate) {
-        List<T> answer = mutate ? asList(self) : toList(self);
-        answer.sort(new NumberAwareComparator<>());
-        return answer;
+    public static boolean isEmpty(Iterable self) {
+        return !self.iterator().hasNext();
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered map using
-     * the closure as a comparator to determine the ordering.
-     * The original map is unchanged.
-     * <pre class="groovyTestCase">def map = [a:5, b:3, c:6, d:4].sort { a, b {@code ->} a.value {@code <=>} b.value }
-     * assert map == [b:3, d:4, a:5, c:6]</pre>
+     * Creates a sub-Map containing the given keys. This method is similar to
+     * List.subList() but uses keys rather than index ranges.
+     * <pre class="groovyTestCase">assert [1:10, 2:20, 4:40].subMap( [2, 4] ) == [2:20, 4:40]</pre>
      *
-     * @param self the original unsorted map
-     * @param closure a Closure used as a comparator
-     * @return the sorted map
-     * @since 1.6.0
+     * @param map  a Map
+     * @param keys a Collection of keys
+     * @return a new Map containing the given keys
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> sort(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>","Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
-        Map<K, V> result = new LinkedHashMap<>();
-        List<Map.Entry<K, V>> entries = asList(self.entrySet());
-        sort((Iterable<Map.Entry<K, V>>) entries, closure);
-        for (Map.Entry<K, V> entry : entries) {
-            result.put(entry.getKey(), entry.getValue());
+    public static <K, V> Map<K, V> subMap(Map<K, V> map, Collection<K> keys) {
+        Map<K, V> answer = new LinkedHashMap<>(keys.size());
+        for (K key : keys) {
+            if (map.containsKey(key)) {
+                answer.put(key, map.get(key));
+            }
         }
-        return result;
+        return answer;
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered Map using
-     * the specified key comparator to determine the ordering.
-     * The original map is unchanged.
-     * <pre class="groovyTestCase">def map = [ba:3, cz:6, ab:5].sort({ a, b {@code ->} a[-1] {@code <=>} b[-1] } as Comparator)
-     * assert map*.value == [3, 5, 6]</pre>
+     * Creates a sub-Map containing the given keys. This method is similar to
+     * List.subList() but uses keys rather than index ranges. The original
+     * map is unaltered.
+     * <pre class="groovyTestCase">
+     * def orig = [1:10, 2:20, 3:30, 4:40]
+     * assert orig.subMap([1, 3] as int[]) == [1:10, 3:30]
+     * assert orig.subMap([2, 4] as Integer[]) == [2:20, 4:40]
+     * assert orig.size() == 4
+     * </pre>
      *
-     * @param self the original unsorted map
-     * @param comparator a Comparator
-     * @return the sorted map
-     * @since 1.7.2
+     * @param map  a Map
+     * @param keys an array of keys
+     * @return a new Map containing the given keys
+     * @since 2.1.0
      */
-    public static <K, V> Map<K, V> sort(Map<K, V> self, Comparator<? super K> comparator) {
-        Map<K, V> result = new TreeMap<>(comparator);
-        result.putAll(self);
-        return result;
+    public static <K, V> Map<K, V> subMap(Map<K, V> map, K[] keys) {
+        Map<K, V> answer = new LinkedHashMap<>(keys.length);
+        for (K key : keys) {
+            if (map.containsKey(key)) {
+                answer.put(key, map.get(key));
+            }
+        }
+        return answer;
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered Map using
-     * the natural ordering of the keys to determine the ordering.
-     * The original map is unchanged.
-     * <pre class="groovyTestCase">map = [ba:3, cz:6, ab:5].sort()
-     * assert map*.value == [5, 3, 6]
-     * </pre>
+     * A helper method to allow lists to work with subscript operators.
+     * <pre class="groovyTestCase">def list = [2, 3]
+     * list[0] = 1
+     * assert list == [1, 3]</pre>
      *
-     * @param self the original unsorted map
-     * @return the sorted map
-     * @since 1.7.2
+     * @param self  a List
+     * @param idx   an index
+     * @param value the value to put at the given index
+     * @since 1.0
      */
-    public static <K, V> Map<K, V> sort(Map<K, V> self) {
-        return new TreeMap<>(self);
+    public static <T> void putAt(List<T> self, int idx, T value) {
+        int size = self.size();
+        idx = normaliseIndex(idx, size);
+        if (idx < size) {
+            self.set(idx, value);
+        } else {
+            while (size < idx) {
+                self.add(size++, null);
+            }
+            self.add(idx, value);
+        }
     }
 
     /**
-     * Sorts the given iterator items into a sorted iterator. The items are
-     * assumed to be comparable. The original iterator will become
-     * exhausted of elements after completing this method call.
-     * A new iterator is produced that traverses the items in sorted order.
-     *
-     * @param self the Iterator to be sorted
-     * @return the sorted items as an Iterator
-     * @since 1.5.5
+     * Support subscript operator for list modification.
      */
-    public static <T> Iterator<T> sort(Iterator<T> self) {
-        return sort((Iterable<T>) toList(self)).listIterator();
+    public static <T> void putAt(List<T> self, Number idx, T value) {
+        putAt(self, idx.intValue(), value);
     }
 
     /**
-     * Sorts the given iterator items into a sorted iterator using the comparator. The
-     * original iterator will become exhausted of elements after completing this method call.
-     * A new iterator is produced that traverses the items in sorted order.
+     * A helper method to allow lists to work with subscript operators.
+     * <pre class="groovyTestCase">
+     * def list = ["a", true]
+     * {@code list[1..<1] = 5}
+     * assert list == ["a", 5, true]
+     * </pre>
      *
-     * @param self       the Iterator to be sorted
-     * @param comparator a Comparator used for comparing items
-     * @return the sorted items as an Iterator
-     * @since 1.5.5
+     * @param self  a List
+     * @param range the (in this case empty) subset of the list to set
+     * @param value the values to put at the given sublist or a Collection of values
+     * @since 1.0
      */
-    public static <T> Iterator<T> sort(Iterator<T> self, Comparator<? super T> comparator) {
-        return sort(toList(self), true, comparator).listIterator();
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, EmptyRange range, Object value) {
+        RangeInfo info = subListBorders(self.size(), range);
+        List sublist = self.subList(info.from, info.to);
+        sublist.clear();
+        if (value instanceof Collection) {
+            Collection col = (Collection) value;
+            if (col.isEmpty()) return;
+            sublist.addAll(col);
+        } else {
+            sublist.add(value);
+        }
     }
 
     /**
-     * Sorts the Iterable using the given Comparator. If the Iterable is a List and mutate
-     * is true, it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <pre class="groovyTestCase">
-     * assert ["hi","hey","hello"] == ["hello","hi","hey"].sort(false, { a, b {@code ->} a.length() {@code <=>} b.length() } as Comparator )
-     * </pre>
+     * A helper method to allow lists to work with subscript operators.
      * <pre class="groovyTestCase">
-     * def orig = ["hello","hi","Hey"]
-     * def sorted = orig.sort(false, String.CASE_INSENSITIVE_ORDER)
-     * assert orig == ["hello","hi","Hey"]
-     * assert sorted == ["hello","Hey","hi"]
+     * def list = ["a", true]
+     * {@code list[1..<1] = [4, 3, 2]}
+     * assert list == ["a", 4, 3, 2, true]
      * </pre>
      *
-     * @param self       the Iterable to be sorted
-     * @param mutate     false will always cause a new list to be created, true will mutate lists in place
-     * @param comparator a Comparator used for the comparison
-     * @return a sorted List
-     * @since 2.2.0
+     * @param self  a List
+     * @param range the (in this case empty) subset of the list to set
+     * @param value the Collection of values
+     * @since 1.0
+     * @see #putAt(java.util.List, groovy.lang.EmptyRange, java.lang.Object)
      */
-    public static <T> List<T> sort(Iterable<T> self, boolean mutate, Comparator<? super T> comparator) {
-        List<T> list = mutate ? asList(self) : toList(self);
-        list.sort(comparator);
-        return list;
+    public static void putAt(List self, EmptyRange range, Collection value) {
+        putAt(self, range, (Object)value);
     }
 
-    /**
-     * Sorts the given iterator items into a sorted iterator using the Closure to determine the correct ordering.
-     * The original iterator will be fully processed after the method call.
-     * <p>
-     * If the closure has two parameters it is used like a traditional Comparator.
-     * I.e.&#160;it should compare its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than, equal to,
-     * or greater than the second respectively. Otherwise, the Closure is assumed
-     * to take a single parameter and return a Comparable (typically an Integer)
-     * which is then used for further comparison.
-     *
-     * @param self    the Iterator to be sorted
-     * @param closure a Closure used to determine the correct ordering
-     * @return the sorted items as an Iterator
-     * @since 1.5.5
-     */
-    public static <T> Iterator<T> sort(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return sort((Iterable<T>) toList(self), closure).listIterator();
+    private static <T> List<T> resizeListWithRangeAndGetSublist(List<T> self, IntRange range) {
+        RangeInfo info = subListBorders(self.size(), range);
+        int size = self.size();
+        if (info.to >= size) {
+            while (size < info.to) {
+                self.add(size++, null);
+            }
+        }
+        List<T> sublist = self.subList(info.from, info.to);
+        sublist.clear();
+        return sublist;
     }
 
     /**
-     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List,
-     * it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <p>
-     * If the Closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b {@code ->} a.length() {@code <=>} b.length() }</pre>
+     * List subscript assignment operator when given a range as the index and
+     * the assignment operand is a collection.
+     * Example: <pre class="groovyTestCase">def myList = [4, 3, 5, 1, 2, 8, 10]
+     * myList[3..5] = ["a", true]
+     * assert myList == [4, 3, 5, "a", true, 10]</pre>
      *
-     * @param self    the Iterable to be sorted
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @see #sort(Iterable, boolean, Closure)
-     * @since 2.2.0
+     * Items in the given
+     * range are replaced with items from the collection.
+     *
+     * @param self  a List
+     * @param range the subset of the list to set
+     * @param col   the collection of values to put at the given sublist
+     * @since 1.5.0
      */
-    public static <T> List<T> sort(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return sort(self, true, closure);
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, IntRange range, Collection col) {
+        List sublist = resizeListWithRangeAndGetSublist(self, range);
+        if (col.isEmpty()) return;
+        sublist.addAll(col);
     }
 
     /**
-     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List
-     * and mutate is true, it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b {@code ->} a.length() {@code <=>} b.length() }</pre>
-     * <pre class="groovyTestCase">
-     * def orig = ["hello","hi","Hey"]
-     * def sorted = orig.sort(false) { it.toUpperCase() }
-     * assert orig == ["hello","hi","Hey"]
-     * assert sorted == ["hello","Hey","hi"]
-     * </pre>
+     * List subscript assignment operator when given a range as the index.
+     * Example: <pre class="groovyTestCase">def myList = [4, 3, 5, 1, 2, 8, 10]
+     * myList[3..5] = "b"
+     * assert myList == [4, 3, 5, "b", 10]</pre>
      *
-     * @param self    the Iterable to be sorted
-     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @since 2.2.0
+     * Items in the given
+     * range are replaced with the operand.  The <code>value</code> operand is
+     * always treated as a single value.
+     *
+     * @param self  a List
+     * @param range the subset of the list to set
+     * @param value the value to put at the given sublist
+     * @since 1.0
      */
-    public static <T> List<T> sort(Iterable<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"})  Closure closure) {
-        List<T> list = mutate ? asList(self) : toList(self);
-        // use a comparator of one item or two
-        int params = closure.getMaximumNumberOfParameters();
-        if (params == 1) {
-            list.sort(new OrderBy<>(closure));
-        } else {
-            list.sort(new ClosureComparator<>(closure));
-        }
-        return list;
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, IntRange range, Object value) {
+        List sublist = resizeListWithRangeAndGetSublist(self, range);
+        sublist.add(value);
     }
 
     /**
-     * Avoids doing unnecessary work when sorting an already sorted set (i.e. an identity function for an already sorted set).
+     * A helper method to allow lists to work with subscript operators.
+     * <pre class="groovyTestCase">def list = ["a", true, 42, 9.4]
+     * list[1, 4] = ["x", false]
+     * assert list == ["a", "x", 42, 9.4, false]</pre>
      *
-     * @param self an already sorted set
-     * @return the set
+     * @param self   a List
+     * @param splice the subset of the list to set
+     * @param values the value to put at the given sublist
      * @since 1.0
      */
-    public static <T> SortedSet<T> sort(SortedSet<T> self) {
-        return self;
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, List splice, Collection values) {
+        if (splice.isEmpty()) {
+            if (!values.isEmpty())
+                throw new IllegalArgumentException("Trying to replace 0 elements with " + values.size() + " elements");
+            return;
+        }
+        Object first = splice.iterator().next();
+        if (first instanceof Integer) {
+            if (values.size() != splice.size())
+                throw new IllegalArgumentException("Trying to replace " + splice.size() + " elements with " + values.size() + " elements");
+            Iterator<?> valuesIter = values.iterator();
+            for (Object index : splice) {
+                putAt(self, (Integer) index, valuesIter.next());
+            }
+        } else {
+            throw new IllegalArgumentException("Can only index a List with another List of Integers, not a List of " + first.getClass().getName());
+        }
     }
 
     /**
-     * Avoids doing unnecessary work when sorting an already sorted map (i.e. an identity function for an already sorted map).
-     *
-     * @param self an already sorted map
-     * @return the map
-     * @since 1.8.1
+     * @deprecated use #putAt(List, List, Collection), retained for binary compatibility
      */
-    public static <K, V> SortedMap<K, V> sort(SortedMap<K, V> self) {
-        return self;
+    @Deprecated
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, List splice, List values) {
+        putAt(self, splice, (Collection) values);
     }
 
     /**
-     * Sorts the Iterable. Assumes that the Iterable elements are
-     * comparable and uses a {@link NumberAwareComparator} to determine the resulting order.
-     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
-     * natural ordering of the Iterable elements. The elements are first placed into a new list which
-     * is then sorted and returned - leaving the original Iterable unchanged.
-     * <pre class="groovyTestCase">
-     * def orig = [1, 3, 2]
-     * def sorted = orig.toSorted()
-     * assert orig == [1, 3, 2]
-     * assert sorted == [1, 2, 3]
-     * </pre>
+     * A helper method to allow lists to work with subscript operators.
+     * <pre class="groovyTestCase">def list = ["a", true, 42, 9.4]
+     * list[1, 3] = 5
+     * assert list == ["a", 5, 42, 5]</pre>
      *
-     * @param self   the Iterable to be sorted
-     * @return the sorted iterable as a List
-     * @see #toSorted(Iterable, Comparator)
-     * @since 2.4.0
+     * @param self   a List
+     * @param splice the subset of the list to set
+     * @param value  the value to put at the given sublist
+     * @since 1.0
      */
-    public static <T> List<T> toSorted(Iterable<T> self) {
-        return toSorted(self, new NumberAwareComparator<>());
+    @SuppressWarnings("unchecked")
+    public static void putAt(List self, List splice, Object value) {
+        if (splice.isEmpty()) {
+            return;
+        }
+        Object first = splice.get(0);
+        if (first instanceof Integer) {
+            for (Object index : splice) {
+                self.set((Integer) index, value);
+            }
+        } else {
+            throw new IllegalArgumentException("Can only index a List with another List of Integers, not a List of "+first.getClass().getName());
+        }
     }
 
     /**
-     * Sorts the Iterable using the given Comparator. The elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * Returns a new <code>Map</code> containing all entries from <code>left</code> and <code>right</code>,
+     * giving precedence to <code>right</code>.  Any keys appearing in both Maps
+     * will appear in the resultant map with values from the <code>right</code>
+     * operand. If the <code>left</code> map is one of TreeMap, LinkedHashMap, Hashtable
+     * or Properties, the returned Map will preserve that type, otherwise a HashMap will
+     * be returned.
+     * <p>
+     * Roughly equivalent to <code>Map m = new HashMap(); m.putAll(left); m.putAll(right); return m;</code>
+     * but with some additional logic to preserve the <code>left</code> Map type for common cases as
+     * described above.
      * <pre class="groovyTestCase">
-     * def orig = ["hello","hi","Hey"]
-     * def sorted = orig.toSorted(String.CASE_INSENSITIVE_ORDER)
-     * assert orig == ["hello","hi","Hey"]
-     * assert sorted == ["hello","Hey","hi"]
+     * assert [a:10, b:20] + [a:5, c:7] == [a:5, b:20, c:7]
      * </pre>
      *
-     * @param self       the Iterable to be sorted
-     * @param comparator a Comparator used for the comparison
-     * @return a sorted List
-     * @since 2.4.0
+     * @param left  a Map
+     * @param right a Map
+     * @return a new Map containing all entries from left and right
+     * @since 1.5.0
      */
-    public static <T> List<T> toSorted(Iterable<T> self, Comparator<? super T> comparator) {
-        List<T> list = toList(self);
-        list.sort(comparator);
-        return list;
+    public static <K, V> Map<K, V> plus(Map<K, V> left, Map<K, V> right) {
+        Map<K, V> map = cloneSimilarMap(left);
+        map.putAll(right);
+        return map;
     }
 
     /**
-     * Sorts this Iterable using the given Closure to determine the correct ordering. The elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <p>
-     * If the Closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b {@code ->} a.length() {@code <=>} b.length() }</pre>
+     * A helper method to allow maps to work with subscript operators
      *
-     * @param self    the Iterable to be sorted
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @see #toSorted(Iterable, Comparator)
-     * @since 2.4.0
+     * @param self  a Map
+     * @param key   an Object as a key for the map
+     * @param value the value to put into the map
+     * @return the value corresponding to the given key
+     * @since 1.0
      */
-    public static <T> List<T> toSorted(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(closure) : new ClosureComparator<>(
-            closure);
-        return toSorted(self, comparator);
+    public static <K,V> V putAt(Map<K,V> self, K key, V value) {
+        self.put(key, value);
+        return value;
     }
 
     /**
-     * Sorts the Iterator. Assumes that the Iterator elements are
-     * comparable and uses a {@link NumberAwareComparator} to determine the resulting order.
-     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
-     * natural ordering of the Iterator elements.
-     * A new iterator is produced that traverses the items in sorted order.
+     * Synonym for {@link #toSpreadMap(java.util.Map)}.
      *
-     * @param self       the Iterator to be sorted
-     * @return the sorted items as an Iterator
-     * @see #toSorted(Iterator, Comparator)
-     * @since 2.4.0
+     * @param self a map
+     * @return a newly created SpreadMap
+     * @since 1.0
      */
-    public static <T> Iterator<T> toSorted(Iterator<T> self) {
-        return toSorted(self, new NumberAwareComparator<>());
+    public static SpreadMap spread(Map self) {
+        return toSpreadMap(self);
     }
 
     /**
-     * Sorts the given iterator items using the comparator. The
-     * original iterator will become exhausted of elements after completing this method call.
-     * A new iterator is produced that traverses the items in sorted order.
+     * Returns a new <code>SpreadMap</code> from this map.
+     * <p>
+     * The example below shows the various possible use cases:
+     * <pre class="groovyTestCase">
+     * def fn(Map m) { return m.a + m.b + m.c + m.d }
      *
-     * @param self       the Iterator to be sorted
-     * @param comparator a Comparator used for comparing items
-     * @return the sorted items as an Iterator
-     * @since 2.4.0
+     * assert fn(a:1, b:2, c:3, d:4) == 10
+     * assert fn(a:1, *:[b:2, c:3], d:4) == 10
+     * assert fn([a:1, b:2, c:3, d:4].toSpreadMap()) == 10
+     * assert fn((['a', 1, 'b', 2, 'c', 3, 'd', 4] as Object[]).toSpreadMap()) == 10
+     * assert fn(['a', 1, 'b', 2, 'c', 3, 'd', 4].toSpreadMap()) == 10
+     * assert fn(['abcd'.toList(), 1..4].transpose().flatten().toSpreadMap()) == 10
+     * </pre>
+     * Note that toSpreadMap() is not normally used explicitly but under the covers by Groovy.
+     *
+     * @param self a map to be converted into a SpreadMap
+     * @return a newly created SpreadMap if this map is not null and its size is positive.
+     * @see groovy.lang.SpreadMap#SpreadMap(java.util.Map)
+     * @since 1.0
      */
-    public static <T> Iterator<T> toSorted(Iterator<T> self, Comparator<? super T> comparator) {
-        return toSorted(toList(self), comparator).listIterator();
+    public static SpreadMap toSpreadMap(Map self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert Map to SpreadMap, because it is null.");
+        else
+            return new SpreadMap(self);
     }
 
     /**
-     * Sorts the given iterator items into a sorted iterator using the Closure to determine the correct ordering.
-     * The original iterator will be fully processed after the method call.
+     * Creates a spreadable map from this list.
      * <p>
-     * If the closure has two parameters it is used like a traditional Comparator.
-     * I.e.&#160;it should compare its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than, equal to,
-     * or greater than the second respectively. Otherwise, the Closure is assumed
-     * to take a single parameter and return a Comparable (typically an Integer)
-     * which is then used for further comparison.
-     *
-     * @param self    the Iterator to be sorted
-     * @param closure a Closure used to determine the correct ordering
-     * @return the sorted items as an Iterator
-     * @see #toSorted(Iterator, Comparator)
-     * @since 2.4.0
+     * @param self a list
+     * @return a newly created SpreadMap
+     * @see groovy.lang.SpreadMap#SpreadMap(java.util.List)
+     * @see #toSpreadMap(java.util.Map)
+     * @since 1.8.0
      */
-    public static <T> Iterator<T> toSorted(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(closure) : new ClosureComparator<>(
-            closure);
-        return toSorted(self, comparator);
+    public static SpreadMap toSpreadMap(List self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert List to SpreadMap, because it is null.");
+        else if (self.size() % 2 != 0)
+            throw new GroovyRuntimeException("Fail to convert List to SpreadMap, because its size is not even.");
+        else
+            return new SpreadMap(self);
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered map using
-     * a {@link NumberAwareComparator} on map entry values to determine the resulting order.
-     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
-     * natural ordering of the Iterator elements. The original map is unchanged.
-     * <pre class="groovyTestCase">
-     * def map = [a:5L, b:3, c:6, d:4.0].toSorted()
-     * assert map.toString() == '[b:3, d:4.0, a:5, c:6]'
-     * </pre>
-     *
-     * @param self the original unsorted map
-     * @return the sorted map
+     * Creates a spreadable map from this iterable.
+     * <p>
+     * @param self an iterable
+     * @return a newly created SpreadMap
+     * @see groovy.lang.SpreadMap#SpreadMap(java.util.List)
+     * @see #toSpreadMap(java.util.Map)
      * @since 2.4.0
      */
-    public static <K, V> Map<K, V> toSorted(Map<K, V> self) {
-        return toSorted(self, new NumberAwareValueComparator<>());
+    @SuppressWarnings("unchecked")
+    public static SpreadMap toSpreadMap(Iterable self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert Iterable to SpreadMap, because it is null.");
+        else
+            return toSpreadMap(asList(self));
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered map using
-     * the supplied comparator to determine the ordering. The original map is unchanged.
+     * Wraps a map using the decorator pattern with a wrapper that intercepts all calls
+     * to <code>get(key)</code>. If an unknown key is found, a default value will be
+     * stored into the Map before being returned. The default value stored will be the
+     * result of calling the supplied Closure with the key as the parameter to the Closure.
+     *
+     * Example usage:
      * <pre class="groovyTestCase">
-     * def keyComparator = [compare: { e1, e2 {@code ->} e1.key {@code <=>} e2.key }] as Comparator
-     * def valueComparator = [compare: { e1, e2 {@code ->} e1.value {@code <=>} e2.value }] as Comparator
-     * def map1 = [a:5, b:3, d:4, c:6].toSorted(keyComparator)
-     * assert map1.toString() == '[a:5, b:3, c:6, d:4]'
-     * def map2 = [a:5, b:3, d:4, c:6].toSorted(valueComparator)
-     * assert map2.toString() == '[b:3, d:4, a:5, c:6]'
+     * def map = [a:1, b:2].withDefault{ k {@code ->} k.toCharacter().isLowerCase() ? 10 : -10 }
+     * def expected = [a:1, b:2, c:10, D:-10]
+     * assert expected.every{ e {@code ->} e.value == map[e.key] }
+     *
+     * def constMap = [:].withDefault{ 42 }
+     * assert constMap.foo == 42
+     * assert constMap.size() == 1
      * </pre>
      *
-     * @param self the original unsorted map
-     * @param comparator a Comparator used for the comparison
-     * @return the sorted map
-     * @since 2.4.0
+     * @param self a Map
+     * @param init a Closure which is passed the unknown key
+     * @return the wrapped Map
+     * @since 1.7.1
+     * @see #withDefault(Map, boolean, boolean, Closure)
      */
-    public static <K, V> Map<K, V> toSorted(Map<K, V> self, Comparator<Map.Entry<K, V>> comparator) {
-        List<Map.Entry<K, V>> sortedEntries = toSorted(self.entrySet(), comparator);
-        Map<K, V> result = new LinkedHashMap<>();
-        for (Map.Entry<K, V> entry : sortedEntries) {
-            result.put(entry.getKey(), entry.getValue());
-        }
-        return result;
+    public static <K, V> Map<K, V> withDefault(Map<K, V> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> init) {
+        return MapWithDefault.newInstance(self, true, false, init);
     }
 
     /**
-     * Sorts the elements from the given map into a new ordered map using
-     * the supplied Closure condition as a comparator to determine the ordering. The original map is unchanged.
-     * <p>
-     * If the closure has two parameters it is used like a traditional Comparator. I.e. it should compare
-     * its two entry parameters for order, returning a negative integer, zero, or a positive integer when the
-     * first parameter is less than, equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single entry parameter and return a Comparable (typically an Integer)
-     * which is then used for further comparison.
+     * Wraps a map using the decorator pattern with a wrapper that intercepts all calls
+     * to <code>get(key)</code> and <code>put(key, value)</code>.
+     * If an unknown key is found for <code>get</code>, a default value will be returned.
+     * The default value will be the result of calling the supplied Closure with the key
+     * as the parameter to the Closure.
+     * If <code>autoGrow</code> is set, the value will be stored into the map.
+     *
+     * If <code>autoShrink</code> is set, then an attempt to <code>put</code> the default value
+     * into the map is ignored and indeed any existing value would be removed.
+     *
+     * If you wish the backing map to be as small as possible, consider setting <code>autoGrow</code>
+     * to <code>false</code> and <code>autoShrink</code> to <code>true</code>.
+     * This keeps the backing map as small as possible, i.e. sparse, but also means that
+     * <code>containsKey</code>, <code>keySet</code>, <code>size</code>, and other methods
+     * will only reflect the sparse values.
+     *
+     * If you are wrapping an immutable map, you should set <code>autoGrow</code>
+     * and <code>autoShrink</code> to <code>false</code>.
+     * In this scenario, the <code>get</code> method is essentially a shorthand
+     * for calling <code>getOrDefault</code> with the default value supplied once as a Closure.
+     *
+     * Example usage:
      * <pre class="groovyTestCase">
-     * def map = [a:5, b:3, c:6, d:4].toSorted { a, b {@code ->} a.value {@code <=>} b.value }
-     * assert map.toString() == '[b:3, d:4, a:5, c:6]'
+     * // sparse map example
+     * def answers = [life: 100].withDefault(false, true){ 42 }
+     * assert answers.size() == 1
+     * assert answers.foo == 42
+     * assert answers.size() == 1
+     * answers.life = 42
+     * answers.putAll(universe: 42, everything: 42)
+     * assert answers.size() == 0
+     *
+     * // immutable map example
+     * def certainties = [death: true, taxes: true].asImmutable().withDefault(false, false){ false }
+     * assert certainties.size() == 2
+     * assert certainties.wealth == false
+     * assert certainties.size() == 2
      * </pre>
      *
-     * @param self the original unsorted map
-     * @param condition a Closure used as a comparator
-     * @return the sorted map
-     * @since 2.4.0
-     */
-    public static <K, V> Map<K, V> toSorted(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>","Map.Entry<K,V>,Map.Entry<K,V>"}) Closure condition) {
-        Comparator<Map.Entry<K,V>> comparator = (condition.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(
-            condition) : new ClosureComparator<>(condition);
-        return toSorted(self, comparator);
-    }
-
-    /**
-     * Avoids doing unnecessary work when sorting an already sorted set
-     *
-     * @param self an already sorted set
-     * @return an ordered copy of the sorted set
-     * @since 2.4.0
+     * @param self a Map
+     * @param autoGrow whether calling get could potentially grow the map if the key isn't found
+     * @param autoShrink whether calling put with the default value could potentially shrink the map
+     * @param init a Closure which is passed the unknown key
+     * @return the wrapped Map
+     * @since 4.0.1
      */
-    public static <T> Set<T> toSorted(SortedSet<T> self) {
-        return new LinkedHashSet<>(self);
+    public static <K, V> Map<K, V> withDefault(Map<K, V> self, boolean autoGrow, boolean autoShrink, @ClosureParams(FirstParam.FirstGenericType.class) Closure<V> init) {
+        return MapWithDefault.newInstance(self, autoGrow, autoShrink, init);
     }
 
     /**
-     * Avoids doing unnecessary work when sorting an already sorted map
+     * An alias for <code>withLazyDefault</code> which decorates a list allowing
+     * it to grow when called with index values outside the normal list bounds.
      *
-     * @param self an already sorted map
-     * @return an ordered copy of the map
-     * @since 2.4.0
+     * @param self a List
+     * @param init a Closure with the target index as parameter which generates the default value
+     * @return the decorated List
+     * @see #withLazyDefault(java.util.List, groovy.lang.Closure)
+     * @see #withEagerDefault(java.util.List, groovy.lang.Closure)
+     * @since 1.8.7
      */
-    public static <K, V> Map<K, V> toSorted(SortedMap<K, V> self) {
-        return new LinkedHashMap<>(self);
+    public static <T> ListWithDefault<T> withDefault(List<T> self, @ClosureParams(value=SimpleType.class, options = "int") Closure<T> init) {
+        return withLazyDefault(self, init);
     }
 
     /**
-     * Removes the initial item from the List.
-     *
+     * Decorates a list allowing it to grow when called with a non-existent index value.
+     * When called with such values, the list is grown in size and a default value
+     * is placed in the list by calling a supplied <code>init</code> Closure. Subsequent
+     * retrieval operations if finding a null value in the list assume it was set
+     * as null from an earlier growing operation and again call the <code>init</code> Closure
+     * to populate the retrieved value; consequently the list can't be used to store null values.
+     * <p>
+     * How it works: The decorated list intercepts all calls
+     * to <code>getAt(index)</code> and <code>get(index)</code>. If an index greater than
... 7652 lines suppressed ...