Skip to content

Commit a1f41d9

Browse files
authored
Merge pull request #2434 from apache/GROOVY-11903
2 parents f7305b3 + af4a151 commit a1f41d9

1 file changed

Lines changed: 106 additions & 101 deletions

File tree

src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java

Lines changed: 106 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -10695,36 +10695,36 @@ public static <K, V> Map.Entry<K, V> min(Map<K, V> self, @ClosureParams(value=Fr
1069510695
* Create a Set composed of the elements of the first Set minus the
1069610696
* elements of the given Collection.
1069710697
*
10698-
* @param self a Set object
10699-
* @param removeMe the items to remove from the Set
10700-
* @return the resulting Set
10698+
* @param self a Set
10699+
* @param removeMe the elements to exclude
10700+
* @return a new Set
1070110701
* @since 1.5.0
1070210702
*/
1070310703
@SuppressWarnings("unchecked")
1070410704
public static <T> Set<T> minus(Set<T> self, Collection<?> removeMe) {
10705-
Comparator comparator = (self instanceof SortedSet) ? ((SortedSet) self).comparator() : null;
10706-
final Set<T> ansSet = createSimilarSet(self);
10707-
ansSet.addAll(self);
10705+
Comparator comparator = self instanceof SortedSet set ? set.comparator() : null;
10706+
Set<T> answer = createSimilarSet(self);
10707+
answer.addAll(self);
1070810708
if (removeMe != null) {
1070910709
for (T o1 : self) {
1071010710
for (Object o2 : removeMe) {
1071110711
boolean areEqual = (comparator != null) ? (comparator.compare(o1, o2) == 0) : coercedEquals(o1, o2);
1071210712
if (areEqual) {
10713-
ansSet.remove(o1);
10713+
answer.remove(o1);
1071410714
}
1071510715
}
1071610716
}
1071710717
}
10718-
return ansSet;
10718+
return answer;
1071910719
}
1072010720

1072110721
/**
1072210722
* Create a Set composed of the elements of the first Set minus the
1072310723
* elements from the given Iterable.
1072410724
*
10725-
* @param self a Set object
10726-
* @param removeMe the items to remove from the Set
10727-
* @return the resulting Set
10725+
* @param self a Set
10726+
* @param removeMe the elements to exclude
10727+
* @return a new Set
1072810728
* @since 1.8.7
1072910729
*/
1073010730
public static <T> Set<T> minus(Set<T> self, Iterable<?> removeMe) {
@@ -10734,29 +10734,29 @@ public static <T> Set<T> minus(Set<T> self, Iterable<?> removeMe) {
1073410734
/**
1073510735
* Create a Set composed of the elements of the first Set minus the given element.
1073610736
*
10737-
* @param self a Set object
10738-
* @param removeMe the element to remove from the Set
10739-
* @return the resulting Set
10737+
* @param self a Set
10738+
* @param removeMe the element to exclude
10739+
* @return a new Set
1074010740
* @since 1.5.0
1074110741
*/
1074210742
@SuppressWarnings("unchecked")
1074310743
public static <T> Set<T> minus(Set<T> self, Object removeMe) {
10744-
Comparator comparator = (self instanceof SortedSet) ? ((SortedSet) self).comparator() : null;
10745-
final Set<T> ansSet = createSimilarSet(self);
10744+
Comparator comparator = self instanceof SortedSet set ? set.comparator() : null;
10745+
Set<T> answer = createSimilarSet(self);
1074610746
for (T t : self) {
10747-
boolean areEqual = (comparator != null)? (comparator.compare(t, removeMe) == 0) : coercedEquals(t, removeMe);
10748-
if (!areEqual) ansSet.add(t);
10747+
boolean areEqual = (comparator != null) ? (comparator.compare(t, removeMe) == 0) : coercedEquals(t, removeMe);
10748+
if (!areEqual) answer.add(t);
1074910749
}
10750-
return ansSet;
10750+
return answer;
1075110751
}
1075210752

1075310753
/**
1075410754
* Create a SortedSet composed of the elements of the first SortedSet minus the
1075510755
* elements of the given Collection.
1075610756
*
10757-
* @param self a SortedSet object
10758-
* @param removeMe the items to remove from the SortedSet
10759-
* @return the resulting SortedSet
10757+
* @param self a SortedSet
10758+
* @param removeMe the elements to exclude
10759+
* @return a new SortedSet
1076010760
* @since 2.4.0
1076110761
*/
1076210762
public static <T> SortedSet<T> minus(SortedSet<T> self, Collection<?> removeMe) {
@@ -10767,9 +10767,9 @@ public static <T> SortedSet<T> minus(SortedSet<T> self, Collection<?> removeMe)
1076710767
* Create a SortedSet composed of the elements of the first SortedSet minus the
1076810768
* elements of the given Iterable.
1076910769
*
10770-
* @param self a SortedSet object
10771-
* @param removeMe the items to remove from the SortedSet
10772-
* @return the resulting SortedSet
10770+
* @param self a SortedSet
10771+
* @param removeMe the elements to exclude
10772+
* @return a new SortedSet
1077310773
* @since 2.4.0
1077410774
*/
1077510775
public static <T> SortedSet<T> minus(SortedSet<T> self, Iterable<?> removeMe) {
@@ -10779,23 +10779,27 @@ public static <T> SortedSet<T> minus(SortedSet<T> self, Iterable<?> removeMe) {
1077910779
/**
1078010780
* Create a SortedSet composed of the elements of the first SortedSet minus the given element.
1078110781
*
10782-
* @param self a SortedSet object
10783-
* @param removeMe the element to remove from the SortedSet
10784-
* @return the resulting SortedSet
10782+
* @param self a SortedSet
10783+
* @param removeMe the element to exclude
10784+
* @return a new SortedSet
1078510785
* @since 2.4.0
1078610786
*/
1078710787
public static <T> SortedSet<T> minus(SortedSet<T> self, Object removeMe) {
1078810788
return (SortedSet<T>) minus((Set<T>) self, removeMe);
1078910789
}
1079010790

1079110791
/**
10792-
* Create a List composed of the elements of the first list minus
10792+
* Create a List composed of the elements of the given List minus
1079310793
* every occurrence of elements of the given Collection.
10794-
* <pre class="groovyTestCase">assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]</pre>
10794+
* <pre class="groovyTestCase">
10795+
* def one = [1, "a", true, true, false, 5.3, null], two = [null, true, 5.3]
10796+
* def sub = one.asUnmodifiable() - two.asUnmodifiable()
10797+
* assert sub == [1, "a", false]
10798+
* </pre>
1079510799
*
1079610800
* @param self a List
10797-
* @param removeMe a Collection of elements to remove
10798-
* @return a List with the given elements removed
10801+
* @param removeMe the elements to exclude
10802+
* @return a new List
1079910803
* @since 1.0
1080010804
*/
1080110805
public static <T> List<T> minus(List<T> self, Collection<?> removeMe) {
@@ -10808,8 +10812,8 @@ public static <T> List<T> minus(List<T> self, Collection<?> removeMe) {
1080810812
* <pre class="groovyTestCase">assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]</pre>
1080910813
*
1081010814
* @param self a Collection
10811-
* @param removeMe a Collection of elements to remove
10812-
* @return a Collection with the given elements removed
10815+
* @param removeMe the elements to exclude
10816+
* @return a new Collection
1081310817
* @since 2.4.0
1081410818
*/
1081510819
public static <T> Collection<T> minus(Collection<T> self, Collection<?> removeMe) {
@@ -10822,8 +10826,8 @@ public static <T> Collection<T> minus(Collection<T> self, Collection<?> removeMe
1082210826
* <pre class="groovyTestCase">assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]</pre>
1082310827
*
1082410828
* @param self a List
10825-
* @param removeMe an Iterable of elements to remove
10826-
* @return a new List with the given elements removed
10829+
* @param removeMe the elements to exclude
10830+
* @return a new List
1082710831
* @since 1.8.7
1082810832
*/
1082910833
public static <T> List<T> minus(List<T> self, Iterable<?> removeMe) {
@@ -10838,8 +10842,8 @@ public static <T> List<T> minus(List<T> self, Iterable<?> removeMe) {
1083810842
* </pre>
1083910843
*
1084010844
* @param self an Iterable
10841-
* @param removeMe an Iterable of elements to remove
10842-
* @return a new Collection with the given elements removed
10845+
* @param removeMe the elements to exclude
10846+
* @return a new Collection
1084310847
* @since 2.4.0
1084410848
*/
1084510849
public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe) {
@@ -10853,10 +10857,10 @@ public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe) {
1085310857
* assert ['a', 'B', 'c', 'D', 'E'].minus(['b', 'C', 'D']) { it.toLowerCase() } == ['a', 'E']
1085410858
* </pre>
1085510859
*
10856-
* @param self an Iterable
10857-
* @param removeMe an Iterable of elements to remove
10858-
* @param condition a Closure used to determine unique items
10859-
* @return a new Collection with the given elements removed
10860+
* @param self an Iterable
10861+
* @param removeMe the elements to exclude
10862+
* @param condition a Closure used to determine uniqueness
10863+
* @return a new Collection
1086010864
* @since 4.0.0
1086110865
*/
1086210866
public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
@@ -10870,67 +10874,66 @@ public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe, @C
1087010874
* Create a new Collection composed of the elements of the first Iterable minus
1087110875
* every matching occurrence as determined by the condition comparator of elements of the given Iterable.
1087210876
* <pre class="groovyTestCase">
10873-
* assert ['a', 'B', 'c', 'D', 'E'].minus(['b', 'C', 'D'], {@code (i, j) -> i.toLowerCase() <=> j.toLowerCase()}) == ['a', 'E']
10877+
* List&lt;String> one = ['a', 'B', 'c', 'D', 'E'], two = ['b', 'C', 'D']
10878+
* def sub = one.minus(two, Comparator.comparing(String::toLowerCase))
10879+
* assert sub == ['a', 'E']
1087410880
* </pre>
1087510881
*
10876-
* @param self an Iterable
10877-
* @param removeMe an Iterable of elements to remove
10882+
* @param self an Iterable
10883+
* @param removeMe the elements to exclude
1087810884
* @param comparator a Comparator
10879-
* @return a new Collection with the given elements removed
10885+
* @return a new Collection
1088010886
* @since 4.0.0
1088110887
*/
10882-
@SuppressWarnings("unchecked")
1088310888
public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe, Comparator<? super T> comparator) {
10884-
Collection<T> ansCollection = createSimilarCollection(self);
10885-
if (!self.iterator().hasNext())
10886-
return ansCollection;
10887-
T head = self.iterator().next();
10888-
10889-
// We can't use the same tactic as for intersection
10890-
// since AbstractCollection only does a remove on the first
10891-
// element it encounters.
10892-
boolean nlgnSort = sameType(new Iterable[]{self, removeMe});
10893-
10894-
if (nlgnSort && (head instanceof Comparable)) {
10895-
//n*LOG(n) version
10896-
Set<T> removeMe2 = new TreeSet<>(comparator);
10897-
for(Object o: removeMe) {
10898-
removeMe2.add((T) o);
10899-
}
10900-
for (T o : self) {
10901-
if (!removeMe2.contains(o))
10902-
ansCollection.add(o);
10903-
}
10904-
} else {
10905-
//n*n version
10906-
Collection<T> tmpAnswer = asCollection(self);
10907-
for (Iterator<T> iter = self.iterator(); iter.hasNext();) {
10908-
T element = iter.next();
10909-
boolean elementRemoved = false;
10910-
for (Iterator<?> iterator = removeMe.iterator(); iterator.hasNext() && !elementRemoved;) {
10911-
Object elt = iterator.next();
10912-
if (DefaultTypeTransformation.compareEqual(element, elt)) {
10913-
iter.remove();
10914-
elementRemoved = true;
10915-
}
10889+
Collection<T> answer = createSimilarCollection(self);
10890+
Iterator<T> iterator = self.iterator();
10891+
if (iterator.hasNext()) {
10892+
T next = iterator.next();
10893+
boolean more = iterator.hasNext();
10894+
Predicate exclude; // the elements of self are discarded if this returns true
10895+
10896+
// We can't use the same tactic as for intersection, since AbstractCollection
10897+
// only does a remove on the first element it encounters.
10898+
if (next instanceof Comparable && sameType(new Iterable[]{self, removeMe})) {
10899+
// O(log(n)) version
10900+
Set removeMe2 = new TreeSet<>(comparator);
10901+
for (Object o : removeMe) {
10902+
removeMe2.add(o);
1091610903
}
10904+
exclude = removeMe2::contains;
10905+
} else {
10906+
// O(n) version
10907+
exclude = (o1) -> {
10908+
for (Object o2 : removeMe) {
10909+
if (DefaultTypeTransformation.compareEqual(o1, o2)) {
10910+
return true;
10911+
}
10912+
}
10913+
return false;
10914+
};
1091710915
}
1091810916

10919-
//remove duplicates
10920-
//can't use treeset since the base classes are different
10921-
ansCollection.addAll(tmpAnswer);
10917+
while (true) {
10918+
if (!exclude.test(next))
10919+
answer.add(next); // include duplicates unless answer dedups
10920+
if (!more) break; else {
10921+
next = iterator.next();
10922+
more = iterator.hasNext();
10923+
}
10924+
}
1092210925
}
10923-
return ansCollection;
10926+
return answer;
1092410927
}
1092510928

1092610929
/**
1092710930
* Create a new List composed of the elements of the first List minus every occurrence of the
1092810931
* given element to remove.
1092910932
* <pre class="groovyTestCase">assert ["a", 5, 5, true] - 5 == ["a", true]</pre>
1093010933
*
10931-
* @param self a List object
10932-
* @param removeMe an element to remove from the List
10933-
* @return the resulting List with the given element removed
10934+
* @param self a List
10935+
* @param removeMe the element to exclude
10936+
* @return a new List
1093410937
* @since 1.0
1093510938
*/
1093610939
public static <T> List<T> minus(List<T> self, Object removeMe) {
@@ -10942,41 +10945,43 @@ public static <T> List<T> minus(List<T> self, Object removeMe) {
1094210945
* given element to remove.
1094310946
* <pre class="groovyTestCase">assert ["a", 5, 5, true] - 5 == ["a", true]</pre>
1094410947
*
10945-
* @param self an Iterable object
10946-
* @param removeMe an element to remove from the Iterable
10947-
* @return the resulting Collection with the given element removed
10948+
* @param self an Iterable
10949+
* @param removeMe an element to exclude
10950+
* @return a new Collection
1094810951
* @since 2.4.0
1094910952
*/
1095010953
public static <T> Collection<T> minus(Iterable<T> self, Object removeMe) {
10951-
Collection<T> ansList = createSimilarCollection(self);
10954+
Collection<T> answer = createSimilarCollection(self);
1095210955
for (T t : self) {
10953-
if (!coercedEquals(t, removeMe)) ansList.add(t);
10956+
if (!coercedEquals(t, removeMe)) {
10957+
answer.add(t);
10958+
}
1095410959
}
10955-
return ansList;
10960+
return answer;
1095610961
}
1095710962

1095810963
/**
1095910964
* Create a Map composed of the entries of the first map minus the
1096010965
* entries of the given map.
1096110966
*
10962-
* @param self a map object
10963-
* @param removeMe the entries to remove from the map
10964-
* @return the resulting map
10967+
* @param self a Map
10968+
* @param removeMe the entries to exclude
10969+
* @return a new Map
1096510970
* @since 1.7.4
1096610971
*/
1096710972
public static <K,V> Map<K,V> minus(Map<K,V> self, Map removeMe) {
10968-
final Map<K,V> ansMap = createSimilarMap(self);
10969-
ansMap.putAll(self);
10973+
Map<K,V> answer = createSimilarMap(self);
10974+
answer.putAll(self);
1097010975
if (removeMe != null && !removeMe.isEmpty()) {
10971-
for (Map.Entry<K, V> e1 : self.entrySet()) {
10972-
for (Object e2 : removeMe.entrySet()) {
10976+
for (var e1 : self.entrySet()) {
10977+
for (var e2 : removeMe.entrySet()) {
1097310978
if (DefaultTypeTransformation.compareEqual(e1, e2)) {
10974-
ansMap.remove(e1.getKey());
10979+
answer.remove(e1.getKey());
1097510980
}
1097610981
}
1097710982
}
1097810983
}
10979-
return ansMap;
10984+
return answer;
1098010985
}
1098110986

1098210987
/**

0 commit comments

Comments
 (0)