@@ -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<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