org.abego.commons.seq.SeqUtil Maven / Gradle / Ivy
/*
* MIT License
*
* Copyright (c) 2020 Udo Borkowski, ([email protected])
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.abego.commons.seq;
import org.abego.commons.lang.exception.MustNotInstantiateException;
import org.abego.commons.util.ListUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.abego.commons.lang.IterableUtil.isEmpty;
import static org.abego.commons.seq.MappedSeq.newMappedSeq;
import static org.abego.commons.seq.SeqForArray.newSeqForArray;
import static org.abego.commons.seq.SeqForIterable.newSeqForIterable;
import static org.abego.commons.seq.SeqForList.newSeqForList;
import static org.abego.commons.seq.SeqNonEmptyUtil.newSeqNonEmpty;
import static org.abego.commons.util.ListUtil.sortedList;
@SuppressWarnings("WeakerAccess")
public final class SeqUtil {
SeqUtil() {
throw new MustNotInstantiateException();
}
/**
* Return an (/the) empty Seq, i.e. a Seq with no items.
*/
public static Seq emptySeq() {
return SeqHelper.emptySeq();
}
/**
* Return true if both {@link Seq}s (seq
and other
)
* are equal, false otherwise.
*
* The implementation does not use {@link Seq#equals(Object)} but
* handles the {@link Seq}s as
* {@link Iterable}s. Therefore this method is typically used in the
* {@link Seq#equals(Object)} code of concrete Seq implementations, like here:
*
* public boolean equals(Object o) {
* if (!(o instanceof Seq)) return false;
*
* return SeqUtil.seqsAreEqual(this, (Seq<?>) o);
* }
*
* Typically a corresponding {@link Seq#hashCode()} implementation then uses
* {@link org.abego.commons.lang.IterableUtil#hashCodeForIterable(Iterable)}
* like here:
*
*
* public int hashCode() {
* return hashCodeForIterable(this);
* }
*
*/
public static boolean seqsAreEqual(Seq> seq, Seq> other) {
return SeqHelper.seqsAreEqual(seq, other);
}
/**
* Return a {@link Seq} with the given items
.
*
* Instead of multiple individual items you may also pass an array of type
* T[]
with items
.
*/
@SafeVarargs
public static Seq newSeq(T... items) {
return items.length == 0 ? SeqHelper.emptySeq() : newSeqForArray(items);
}
/**
* Return a {@link Seq} with the items of the given list
.
*
* The list must not change after the Seq is created.
*/
public static Seq newSeq(List list) {
return list.isEmpty() ? SeqHelper.emptySeq() : newSeqForList(list);
}
/**
* Return a {@link Seq} for the given iterable
.
*
* The Iterable must not change after the Seq is created.
*/
public static Seq newSeq(Iterable iterable) {
return isEmpty(iterable) ? SeqHelper.emptySeq() : newSeqForIterable(iterable);
}
@SuppressWarnings("unchecked")
public static Seq newSeq(Stream stream) {
return SeqUtil.newSeq((T @NonNull []) stream.toArray());
}
/**
* Return a {@link Seq} with the given item
or an empty Seq
* if the item is {@code null}.
*/
public static Seq newSeqOfNullable(@Nullable T item) {
return item == null ? SeqUtil.emptySeq() : newSeq(item);
}
/**
* Return a new {@link Seq} consisting of the items of seq
that match
* the predicate
.
*/
public static Seq filter(Seq seq, Predicate condition) {
return newSeq(seq.stream().filter(condition).collect(Collectors.toList()));
}
/**
* Return a new {@link Seq} consisting of the results of applying the given
* mapper
function to the elements of the seq
.
*/
public static Seq map(Seq seq, Function super T, ? extends R> mapper) {
return newMappedSeq(seq, mapper);
}
/**
* Return a new {@link Seq} consisting of the elements of iterable
* sorted by the given sortKey
.
*/
public static > Seq sortedBy(
Iterable iterable, Function super T, ? extends S> sortKey) {
return newSeq(ListUtil.toSortedList(iterable, Comparator.comparing(sortKey)));
}
/**
* Return a new {@link Seq} consisting of the elements of iterable
,
* sorted in ascending order, according to the {@linkplain Comparable
* natural ordering} of its elements.
*
* All elements in the iterable must implement the {@link Comparable}
* interface. Furthermore, all elements in the iterable must be
* mutually comparable (that is, {@code e1.compareTo(e2)}
* must not throw a {@code ClassCastException} for any elements
* {@code e1} and {@code e2} in the iterable).
*/
public static Seq sorted(Iterable iterable) {
List list = ListUtil.toList(iterable);
list.sort(null);
return newSeq(list);
}
/**
* Return a new {@link Seq} consisting of the elements of iterable
,
* sorted in ascending order, according to the given comparator
.
*
* All elements in the iterable must be mutually comparable using the
* specified comparator (that is, {@code c.compare(e1, e2)} must not throw
* a {@code ClassCastException} for any elements {@code e1} and {@code e2}
* in the iterable).
*/
public static Seq sorted(Iterable iterable, Comparator super T> comparator) {
List list = ListUtil.toList(iterable);
list.sort(comparator);
return newSeq(list);
}
/**
* Return the items of the iterable
in groups of equal items, with the equality defined by the
* comparator
.
*/
public static Seq> groupedBy(Iterable iterable, Comparator comparator) {
List> result = new ArrayList<>();
@Nullable
List currentGroup = null;
for (T item : sortedList(iterable, comparator)) {
if (currentGroup == null) {
currentGroup = ListUtil.list(item);
} else if (comparator.compare(currentGroup.get(0), item) == 0) {
currentGroup.add(item);
} else {
result.add(newSeqNonEmpty(currentGroup));
currentGroup = ListUtil.list(item);
}
}
if (currentGroup != null) {
result.add(newSeqNonEmpty(currentGroup));
}
return SeqUtil.newSeq(result);
}
/**
* Returns a sequence of objects of type R
, with each object
* representing the result of merging groups of items of the
* iterable
according to the mergeFunction
and
* the groups defined by the comparator
.
*
* In detail:
*
* - Group the items of the
iterable
by the
* comparator
, i.e. items that are "equal" according to
* the comparator are in the same group.
* - Merge the items of each group to a single object of type
*
R
using the mergeFunction
.
* - Return the sequence of all merged objects, in the order defined
* by the comparator
*
*/
public static Seq groupedAndMerged(
Iterable iterable,
Comparator comparator,
Function, R> mergeFunction) {
return groupedBy(iterable, comparator).map(mergeFunction);
}
public static Seq reverse(Seq seq) {
List result = new ArrayList<>();
for (int i = seq.size() - 1; i >= 0; i--) {
result.add(seq.item(i));
}
return newSeq(result);
}
}