You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/10/01 22:18:03 UTC
[groovy] branch master updated: GROOVY-10275: Align intersect which
takes a closure/comparator ordering to be the same as other languages.
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 903366a GROOVY-10275: Align intersect which takes a closure/comparator ordering to be the same as other languages.
903366a is described below
commit 903366a781796910047add22a70f1bd888a3a4a8
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Sep 30 19:24:44 2021 +1000
GROOVY-10275: Align intersect which takes a closure/comparator ordering to be the same as other languages.
---
.../groovy/runtime/DefaultGroovyMethods.java | 75 ++++++++++++++++++----
src/test/groovy/GroovyMethodsTest.groovy | 3 +-
src/test/groovy/ListTest.groovy | 8 ++-
3 files changed, 68 insertions(+), 18 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 69f80f0..a6bc8f4 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -12651,6 +12651,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* For collections of custom objects; the objects should implement java.lang.Comparable
* <pre class="groovyTestCase">
* assert [3,4] == [1,2,3,4].intersect([3,4,5,6], Comparator.naturalOrder())
+ * assert [2,4] == [1,2,3,4].intersect([4,8,12,16,20], (x, y) {@code -> x * x <=> y})
* </pre>
* <pre class="groovyTestCase">
* def one = ['a', 'B', 'c', 'd']
@@ -12658,8 +12659,8 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* def compareIgnoreCase = { a, b {@code ->} a.toLowerCase() {@code <=>} b.toLowerCase() }
* assert one.intersect(two) == ['d']
* assert two.intersect(one) == ['d']
- * assert one.intersect(two, compareIgnoreCase) == ['b', 'C', 'd']
- * assert two.intersect(one, compareIgnoreCase) == ['B', 'c', 'd']
+ * assert one.intersect(two, compareIgnoreCase) == ['B', 'c', 'd']
+ * assert two.intersect(one, compareIgnoreCase) == ['b', 'C', 'd']
* </pre>
*
* @param left a Collection
@@ -12674,11 +12675,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
Collection<T> result = createSimilarCollection(left, Math.min(left.size(), right.size()));
//creates the collection to look for values.
- Collection<T> pickFrom = new TreeSet<>(comparator);
- pickFrom.addAll(left);
+ Collection<T> compareWith = new TreeSet<>(comparator);
+ compareWith.addAll(right);
- for (final T t : right) {
- if (pickFrom.contains(t))
+ for (final T t : left) {
+ if (compareWith.contains(t))
result.add(t);
}
return result;
@@ -12688,7 +12689,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* Create a Collection composed of the intersection of both iterables. Any
* elements that exist in both iterables are added to the resultant collection.
* For iterables of custom objects; the objects should implement java.lang.Comparable
- * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+ * <pre class="groovyTestCase">
+ * assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])
+ * </pre>
* By default, Groovy uses a {@link NumberAwareComparator} when determining if an
* element exists in both collections.
*
@@ -12706,7 +12709,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* Create a Collection composed of the intersection of both iterables. Any
* elements that exist in both iterables are added to the resultant collection.
* For iterables of custom objects; the objects should implement java.lang.Comparable
- * <pre class="groovyTestCase">assert [3,4] == [1,2,3,4].intersect([3,4,5,6], Comparator.naturalOrder())</pre>
+ * <pre class="groovyTestCase">
+ * assert [3,4] == [1,2,3,4].intersect([3,4,5,6], Comparator.naturalOrder())
+ * </pre>
*
* @param left an Iterable
* @param right an Iterable
@@ -12719,9 +12724,41 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
}
/**
+ * Create a Collection composed of the intersection of both iterables.
+ * Elements from teh first iterable which also occur (according to the comparator closure) in the second iterable are added to the result.
+ * 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 deemed equal).
+ * <pre class="groovyTestCase">
+ * def one = ['a', 'B', 'c', 'd']
+ * def two = ['b', 'C', 'd', 'e']
+ * def compareIgnoreCase = { it.toLowerCase() }
+ * assert one.intersect(two, compareIgnoreCase) == ['B', 'c', 'd']
+ * assert two.intersect(one, compareIgnoreCase) == ['b', 'C', 'd']
+ * </pre>
+ *
+ * @param left an Iterable
+ * @param right an Iterable
+ * @param condition a Closure used to determine unique items
+ * @return a Collection as an intersection of both iterables
+ * @since 4.0.0
+ */
+ public static <T> Collection<T> intersect(Iterable<T> left, Iterable<T> right, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+ Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+ ? new OrderBy<>(condition, true)
+ : new ClosureComparator<>(condition);
+ return intersect(left, right, comparator);
+ }
+
+ /**
* Create a List composed of the intersection of a List and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+ * <pre class="groovyTestCase">
+ * assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])
+ * </pre>
* By default, Groovy uses a {@link NumberAwareComparator} when determining if an
* element exists in both collections.
*
@@ -12738,7 +12775,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
/**
* Create a List composed of the intersection of a List and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [3,4] == [1,2,3,4].intersect([3,4,5,6])</pre>
+ * <pre class="groovyTestCase">
+ * assert [3,4] == [1,2,3,4].intersect([3,4,5,6])
+ * </pre>
*
* @param left a List
* @param right an Iterable
@@ -12753,7 +12792,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
/**
* Create a Set composed of the intersection of a Set and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [4,5] as Set == ([1,2,3,4,5] as Set).intersect([4,5,6,7,8])</pre>
+ * <pre class="groovyTestCase">
+ * assert [4,5] as Set == ([1,2,3,4,5] as Set).intersect([4,5,6,7,8])
+ * </pre>
* By default, Groovy uses a {@link NumberAwareComparator} when determining if an
* element exists in both collections.
*
@@ -12770,7 +12811,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
/**
* Create a Set composed of the intersection of a Set and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [3,4] as Set == ([1,2,3,4] as Set).intersect([3,4,5,6], Comparator.naturalOrder())</pre>
+ * <pre class="groovyTestCase">
+ * assert [3,4] as Set == ([1,2,3,4] as Set).intersect([3,4,5,6], Comparator.naturalOrder())
+ * </pre>
*
* @param left a Set
* @param right an Iterable
@@ -12785,7 +12828,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
/**
* Create a SortedSet composed of the intersection of a SortedSet and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])</pre>
+ * <pre class="groovyTestCase">
+ * assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])
+ * </pre>
* By default, Groovy uses a {@link NumberAwareComparator} when determining if an
* element exists in both collections.
*
@@ -12802,7 +12847,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
/**
* Create a SortedSet composed of the intersection of a SortedSet and an Iterable. Any
* elements that exist in both iterables are added to the resultant collection.
- * <pre class="groovyTestCase">assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])</pre>
+ * <pre class="groovyTestCase">
+ * assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])
+ * </pre>
*
* @param left a SortedSet
* @param right an Iterable
diff --git a/src/test/groovy/GroovyMethodsTest.groovy b/src/test/groovy/GroovyMethodsTest.groovy
index 1098a45..91803d7 100644
--- a/src/test/groovy/GroovyMethodsTest.groovy
+++ b/src/test/groovy/GroovyMethodsTest.groovy
@@ -1597,7 +1597,8 @@ class GroovyMethodsTest extends GroovyTestCase {
def list1 = [[language: 'Java'], [language: 'Groovy'], [language: 'Scala']]
def list2 = [[language: 'Groovy'], [language: 'JRuby'], [language: 'Java']]
def intersection = list1.intersect(list2)
- assert intersection == [[language: 'Groovy'], [language: 'Java']]
+ assert intersection == [[language: 'Java'], [language: 'Groovy']]
+ assert list2.intersect(list1) == [[language: 'Groovy'], [language: 'Java']]
def locs1 = [[loc: [0, 1]], [loc: [1, 1]]]
def locs2 = [[loc: [2, 1]], [loc: [1, 1]]]
diff --git a/src/test/groovy/ListTest.groovy b/src/test/groovy/ListTest.groovy
index 8a92f54..8e892a0 100644
--- a/src/test/groovy/ListTest.groovy
+++ b/src/test/groovy/ListTest.groovy
@@ -170,12 +170,14 @@ class ListTest extends GroovyTestCase {
void testIntersect() {
def l1 = [1, 1, "wrer", 2, 3, 3, "wrewer", 4, 5, "w", "w"]
def l2 = [1, 2, "f", "w"]
- assert l1.intersect(l2) == [1, 2, "w"]
+ assert l1.intersect(l2) == [1, 1, 2, 'w', 'w']
+ assert l2.intersect(l1) == [1, 2, "w"]
- // GROOVY-1006
+ // GROOVY-1006
l1 = [1, 1.0, "wrer", 2, 3, 3L, "wrewer", 4, 5, "w", "w"]
l2 = [(double) 1, 2L, "f", "w"]
- assert l1.intersect(l2) == [1, 2, "w"]
+ assert l1.intersect(l2) == [1, 1.0, 2, 'w', 'w']
+ assert l2.intersect(l1) == [1, 2, "w"]
}
// GROOVY-1006