From 04b05e725d09fe077c12a67be5639f57b5612e9f Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Mon, 3 Aug 2026 15:03:00 +0300 Subject: [PATCH 1/3] [COLLECTIONS-897] Add LexicographicPermutationIterator Add an Iterator> that generates the permutations of a collection in lexicographical order, complementing PermutationIterator, which uses the Steinhaus-Johnson-Trotter ordering. Elements are ordered by their natural ordering, or by a Comparator supplied to the two-argument constructor, which also allows permuting elements that do not implement Comparable. Each call to next() advances by the standard next-permutation step: locate the pivot, swap it with its successor, then reverse the descending tail. Equal elements are not distinguished, so an input with duplicates yields fewer than n! permutations. An empty collection yields exactly one empty list, as 0! = 1. remove() is unsupported. Comparator dispatch follows the java.util.TreeMap pattern of testing the comparator field for null on each comparison; benchmarking showed no measurable difference against normalizing null to Comparator.naturalOrder() in the constructor. Tests extend AbstractIteratorTest to cover the Iterator contract, and add cases for lexicographical exhaustivity, duplicate handling, custom and reverse comparators, non-Comparable elements, stream traversal, exhaustion, and equals/hashCode. --- .../LexicographicPermutationIterator.java | 198 ++++++++++ .../LexicographicPermutationIteratorTest.java | 343 ++++++++++++++++++ 2 files changed, 541 insertions(+) create mode 100644 src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java create mode 100644 src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java diff --git a/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java new file mode 100644 index 0000000000..3389db68b2 --- /dev/null +++ b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; + +/** + * This iterator creates permutations of an input collection, using the + * lexicographical order. + *

+ * The iterator might return fewer than n! permutations of the input collection, + * because duplicated permutations are skipped: equal elements are not + * distinguished from one another. + * The {@code remove()} operation is not supported, and will throw an + * {@code UnsupportedOperationException}. + *

+ *

+ * NOTE: in case an empty collection is provided, the iterator will + * return exactly one empty list as result, as 0! = 1. + *

+ * + * @param the type of the objects being permuted + * @see PermutationIterator + * @since 4.6.0 + */ +public class LexicographicPermutationIterator implements Iterator> { + + /** + * The comparator used to define order of generation, + * or null if it uses the natural ordering. + */ + private final Comparator comparator; + + /** + * Next permutation to return. When a permutation is requested + * this instance is provided and the next one is computed. + */ + private List nextPermutation; + + /** + * Standard constructor for this class, using the natural ordering of the elements. + * + * @param collection The collection to generate permutations for + * @throws NullPointerException if collection is null + */ + public LexicographicPermutationIterator(final Collection collection) { + this(collection, null); + } + + /** + * Constructs an instance using the given comparator to order the elements. + * + * @param collection The collection to generate permutations for + * @param comparator The comparator used to define the order of generation, + * or null to use the natural ordering of the elements + * @throws NullPointerException if collection is null + */ + public LexicographicPermutationIterator(final Collection collection, final Comparator comparator) { + Objects.requireNonNull(collection, "collection"); + nextPermutation = new ArrayList<>(collection); + this.comparator = comparator; + } + + /** + * Indicates if there are more permutation available. + * + * @return true if there are more permutations, otherwise false + */ + @Override + public boolean hasNext() { + return nextPermutation != null; + } + + /** + * Returns the next permutation of the input collection. + * + * @return A list of the permutator's elements representing a permutation + * @throws NoSuchElementException if there are no more permutations + */ + @Override + public List next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + final int size = nextPermutation.size(); + List nextP = null; + + // find the pivot: the rightmost element that is smaller than its successor. + // if there is none the current permutation is the last one in lexicographical order + int i = size - 2; + while (i >= 0 && compareElements(nextPermutation.get(i), nextPermutation.get(i + 1)) >= 0) { + --i; + } + + if (i >= 0) { + // find the rightmost element greater than the pivot; the tail is descending, + // so this is the pivot's successor in the remaining elements + int j = size - 1; + while (j >= i && compareElements(nextPermutation.get(i), nextPermutation.get(j)) >= 0) { + --j; + } + + // swap the pivot with its successor, then reverse the descending tail + // into ascending order to obtain the smallest larger permutation + nextP = new ArrayList<>(nextPermutation); + Collections.swap(nextP, i, j); + final List subList = nextP.subList(i + 1, nextP.size()); + Collections.reverse(subList); + } + + final List result = nextPermutation; + nextPermutation = nextP; + return result; + } + + /** + * Always throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException Always thrown. + */ + @Override + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + + /** + * Compares this iterator to another for equality. Two iterators are equal when + * they use equal comparators and are positioned at an equal next permutation. + * + * @param o The object to compare to this instance + * @return true if the given object is an equal iterator, otherwise false + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + final LexicographicPermutationIterator that = (LexicographicPermutationIterator) o; + return Objects.equals(comparator, that.comparator) && Objects.equals(nextPermutation, that.nextPermutation); + } + + /** + * Returns a hash code consistent with {@link #equals(Object)}. Note that the + * hash code changes as the iterator advances. + * + * @return A hash code for this instance + */ + @Override + public int hashCode() { + return Objects.hash(comparator, nextPermutation); + } + + /** + * Compares two elements using the comparator, or their natural ordering if no + * comparator was supplied. + * + * @param e1 The first element to compare + * @param e2 The second element to compare + * @return a negative integer, zero, or a positive integer as the first element + * is less than, equal to, or greater than the second + * @throws ClassCastException if no comparator was supplied and the elements are + * not mutually {@link Comparable} + */ + @SuppressWarnings("unchecked") + private int compareElements(final E e1, final E e2) { + return comparator == null + ? ((Comparable) e1).compareTo(e2) + : comparator.compare(e1, e2); + } + +} diff --git a/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java b/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java new file mode 100644 index 0000000000..c20dd8a13b --- /dev/null +++ b/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java @@ -0,0 +1,343 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Test class for LexicographicPermutationIterator. + */ +class LexicographicPermutationIteratorTest extends AbstractIteratorTest> { + + /** + * A comparator that orders nothing, identified only by an id, used to check that + * equal comparators make equal iterators. + * + * @param the type of the objects compared + */ + private static final class CustomComparator implements Comparator { + + private final int id; + + CustomComparator(final int id) { + this.id = id; + } + + @Override + public int compare(final T o1, final T o2) { + return 0; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + final CustomComparator cmp = (CustomComparator) o; + return id == cmp.id; + } + + @Override + public int hashCode() { + return id; + } + } + + /** + * A value holder that deliberately does not implement {@link Comparable}, used to + * check that a supplied comparator is honored. + * + * @param the type of the wrapped value + */ + private static final class NonComparableObject { + + private final T value; + + NonComparableObject(final T value) { + this.value = value; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + final NonComparableObject that = (NonComparableObject) o; + return Objects.equals(value, that.value); + } + + T getValue() { + return value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } + + @SuppressWarnings("boxing") // OK in test code + protected Character[] testArray = { 'A', 'B', 'C' }; + + protected List testList; + + @Override + public LexicographicPermutationIterator makeEmptyIterator() { + return new LexicographicPermutationIterator<>(new ArrayList<>()); + } + + @Override + public LexicographicPermutationIterator makeObject() { + return new LexicographicPermutationIterator<>(testList); + } + + @BeforeEach + public void setUp() { + testList = new ArrayList<>(); + testList.addAll(Arrays.asList(testArray)); + } + + @Override + public boolean supportsEmptyIterator() { + return false; + } + + @Override + public boolean supportsRemove() { + return false; + } + + @Test + void testCustomComparator() { + final Iterator> permutationIterator = new LexicographicPermutationIterator<>(Arrays.asList('C', 'B', 'A'), + Comparator.reverseOrder()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'B', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'C', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'C'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'C', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B', 'C'), permutationIterator.next()); + + assertFalse(permutationIterator.hasNext()); + } + + @Test + void testCustomComparatorWithNonComparableObjects() { + final Iterator>> permutationIterator = + new LexicographicPermutationIterator<>(Arrays.asList( + new NonComparableObject<>('A'), + new NonComparableObject<>('B')), Comparator.comparing(NonComparableObject::getValue)); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList( + new NonComparableObject<>('A'), + new NonComparableObject<>('B')), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList( + new NonComparableObject<>('B'), + new NonComparableObject<>('A')), permutationIterator.next()); + + assertFalse(permutationIterator.hasNext()); + } + + @Test + void testDuplicatedPermutationsAreSkipped() { + final Iterator> permutationIterator = new LexicographicPermutationIterator<>(Arrays.asList('A', 'A', 'B', 'B')); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'A', 'B', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B', 'A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B', 'B', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'B', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'B', 'A', 'A'), permutationIterator.next()); + + assertFalse(permutationIterator.hasNext()); + } + + @Test + void testEmptyCollection() { + final Iterator> permutationIterator = makeEmptyIterator(); + + // there is one permutation for an empty set: 0! = 1 + assertTrue(permutationIterator.hasNext()); + assertTrue(permutationIterator.next().isEmpty()); + + assertFalse(permutationIterator.hasNext()); + } + + @Test + void testEqualsForEqualCollections() { + final Iterator> one = new LexicographicPermutationIterator<>(emptyList()); + final Iterator> another = new LexicographicPermutationIterator<>(emptyList()); + + assertEquals(one, another); + } + + @Test + void testEqualsForEqualCollectionsAndComparators() { + final Iterator> one = new LexicographicPermutationIterator<>(emptyList(), new CustomComparator<>(42)); + final Iterator> another = new LexicographicPermutationIterator<>(emptyList(), new CustomComparator<>(42)); + + assertEquals(one, another); + } + + @Test + void testHashCodeForEqualCollections() { + final Iterator> one = new LexicographicPermutationIterator<>(emptyList()); + final Iterator> another = new LexicographicPermutationIterator<>(emptyList()); + + assertEquals(one.hashCode(), another.hashCode()); + } + + @Test + void testHashCodeForEqualCollectionsAndComparators() { + final Iterator> one = new LexicographicPermutationIterator<>(emptyList(), new CustomComparator<>(42)); + final Iterator> another = new LexicographicPermutationIterator<>(emptyList(), new CustomComparator<>(42)); + + assertEquals(one.hashCode(), another.hashCode()); + } + + @Test + void testNonComparableElementsThrow() { + final Iterator>> permutationIterator = new LexicographicPermutationIterator<>( + Arrays.asList( + new NonComparableObject<>('A'), + new NonComparableObject<>('B'))); + + assertTrue(permutationIterator.hasNext()); + assertThrows(ClassCastException.class, permutationIterator::next); + } + + @Test + void testPermutationException() { + final Iterator> permutationIterator = new LexicographicPermutationIterator<>(Arrays.asList('A', 'B')); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A'), permutationIterator.next()); + + // asking for another permutation should throw an exception + assertFalse(permutationIterator.hasNext()); + assertThrows(NoSuchElementException.class, permutationIterator::next); + } + + /** + * test checking that all the permutations are returned in lexicographical order + */ + @Test + void testPermutationExhaustivity() { + final Iterator> permutationIterator = makeObject(); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B', 'C'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'C', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'C'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'C', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'B', 'A'), permutationIterator.next()); + + assertFalse(permutationIterator.hasNext()); + } + + @Test + void testRemoveThrows() { + final Iterator> permutationIterator = makeObject(); + + assertTrue(permutationIterator.hasNext()); + assertThrows(UnsupportedOperationException.class, permutationIterator::remove); + } + + @Test + void testStreamOfPermutations() { + final Iterable> iterable = this::makeObject; + + final List> allPermutations = StreamSupport.stream(iterable.spliterator(), false) + .collect(Collectors.toList()); + + assertEquals(Arrays.asList( + Arrays.asList('A', 'B', 'C'), + Arrays.asList('A', 'C', 'B'), + Arrays.asList('B', 'A', 'C'), + Arrays.asList('B', 'C', 'A'), + Arrays.asList('C', 'A', 'B'), + Arrays.asList('C', 'B', 'A')), allPermutations); + } + +} From fb5995493234fd1e218a344e2032684e6ba2536c Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Wed, 12 Aug 2026 18:27:44 +0300 Subject: [PATCH 2/3] Documentation improvements --- .../LexicographicPermutationIterator.java | 38 +++++++++++++- .../LexicographicPermutationIteratorTest.java | 51 +++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java index 3389db68b2..1c4f1f495c 100644 --- a/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java +++ b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java @@ -29,9 +29,27 @@ * This iterator creates permutations of an input collection, using the * lexicographical order. *

+ * Iteration starts at the arrangement in which the elements are given, and each + * call to {@code next()} advances to the smallest arrangement greater than the + * current one. Iteration therefore ends at the largest arrangement, and the ones + * preceding the given arrangement are never returned: only a collection already + * sorted according to the ordering in use yields the complete set of + * permutations. Callers wanting the complete set must sort the collection + * beforehand, just as callers of + * {@link java.util.Collections#binarySearch(java.util.List, Object) binarySearch} + * must. Callers wanting to enumerate one part of the set, to resume from a + * previously reached arrangement or to split the work, may start anywhere. + *

+ *

+ * The starting arrangement is the iteration order of the given collection, so + * collections whose iteration order is unspecified, such as {@link java.util.HashSet}, + * make poor input: which permutations are returned is then unspecified too. + *

+ *

* The iterator might return fewer than n! permutations of the input collection, - * because duplicated permutations are skipped: equal elements are not - * distinguished from one another. + * either because the collection was not sorted according to the ordering in use, + * as described above, or because duplicated permutations are skipped: equal + * elements are not distinguished from one another. * The {@code remove()} operation is not supported, and will throw an * {@code UnsupportedOperationException}. *

@@ -39,6 +57,11 @@ * NOTE: in case an empty collection is provided, the iterator will * return exactly one empty list as result, as 0! = 1. *

+ *

+ * NOTE: {@link PermutationIterator} differs on both counts. It returns exactly n! + * permutations whatever the order of the input collection. The two iterators are + * therefore not interchangeable. + *

* * @param the type of the objects being permuted * @see PermutationIterator @@ -60,6 +83,10 @@ public class LexicographicPermutationIterator implements Iterator> { /** * Standard constructor for this class, using the natural ordering of the elements. + *

+ * Iteration starts at the arrangement in which the collection iterates its + * elements; sort the collection first to obtain the complete set of permutations. + *

* * @param collection The collection to generate permutations for * @throws NullPointerException if collection is null @@ -70,6 +97,11 @@ public LexicographicPermutationIterator(final Collection collection /** * Constructs an instance using the given comparator to order the elements. + *

+ * Iteration starts at the arrangement in which the collection iterates its + * elements; sort the collection with the same comparator first to obtain the + * complete set of permutations. + *

* * @param collection The collection to generate permutations for * @param comparator The comparator used to define the order of generation, @@ -97,6 +129,8 @@ public boolean hasNext() { * * @return A list of the permutator's elements representing a permutation * @throws NoSuchElementException if there are no more permutations + * @throws ClassCastException if no comparator was supplied and the elements are + * not mutually {@link Comparable} */ @Override public List next() { diff --git a/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java b/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java index c20dd8a13b..c0ca12c357 100644 --- a/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java +++ b/src/test/java/org/apache/commons/collections4/iterators/LexicographicPermutationIteratorTest.java @@ -340,4 +340,55 @@ void testStreamOfPermutations() { Arrays.asList('C', 'B', 'A')), allPermutations); } + /** + * test checking that iteration starts at the given arrangement rather than at the + * smallest one, so that a collection which is not sorted yields only the + * permutations that follow it. Sorting the input is the caller's responsibility, + * as it is for binarySearch. + */ + @Test + void testUnsortedCollectionStartsAtGivenArrangement() { + final Iterator> permutationIterator = new LexicographicPermutationIterator<>(Arrays.asList('B', 'A', 'C')); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'C'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'C', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'A', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('C', 'B', 'A'), permutationIterator.next()); + + // the two permutations starting with 'A' precede the given arrangement + // and are therefore never returned + assertFalse(permutationIterator.hasNext()); + } + + /** + * test checking that the starting arrangement is honoured for a supplied comparator + * too, the permutations preceding it under that comparator being left out. + */ + @Test + void testUnsortedCollectionStartsAtGivenArrangementWithComparator() { + final Iterator> permutationIterator = new LexicographicPermutationIterator<>(Arrays.asList('B', 'C', 'A'), + Comparator.reverseOrder()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'C', 'A'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('B', 'A', 'C'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'C', 'B'), permutationIterator.next()); + + assertTrue(permutationIterator.hasNext()); + assertEquals(Arrays.asList('A', 'B', 'C'), permutationIterator.next()); + + assertFalse(permutationIterator.hasNext()); + } + } From 12278fa4d56e2ab5c6c7900e007c64abf591c940 Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Wed, 12 Aug 2026 18:51:33 +0300 Subject: [PATCH 3/3] bump-up to the next release version 4.7.0 --- .../iterators/LexicographicPermutationIterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java index 1c4f1f495c..f4a0089cd0 100644 --- a/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java +++ b/src/main/java/org/apache/commons/collections4/iterators/LexicographicPermutationIterator.java @@ -65,7 +65,7 @@ * * @param the type of the objects being permuted * @see PermutationIterator - * @since 4.6.0 + * @since 4.7.0 */ public class LexicographicPermutationIterator implements Iterator> {