io.github.selcukes.collections.Streams Maven / Gradle / Ivy
/*
* Copyright (c) Ramesh Babu Prudhvi.
*
* Licensed 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
*
* http://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 io.github.selcukes.collections;
import lombok.experimental.UtilityClass;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@UtilityClass
public class Streams {
/**
* It takes an iterator and returns a stream.
*
* @param iterator The iterator to convert to a stream.
* @return A stream of the iterator.
*/
public Stream of(final Iterator extends T> iterator) {
return StreamSupport
.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false);
}
/**
* Returns an OptionalInt that contains the index of the first element in
* the list that matches the given predicate, or an empty OptionalInt if no
* such element exists.
*
* This method converts the input list to a Stream using the of() method,
* filters the stream using the provided predicate, and returns the index of
* the first element that matches the predicate using the findFirst()
* method. If no element matches the predicate, an empty OptionalInt is
* returned.
*
* @param elements the list of elements to search through
* @param predicate the predicate to apply to the elements
* @return an OptionalInt containing the index of the first
* matching element, or an empty OptionalInt if no such
* element exists
*/
public OptionalInt indexOf(List elements, Predicate predicate) {
return of(elements).parallel()
.filter(i -> predicate.test(elements.get(i)))
.findFirst();
}
/**
* Returns an {@code Optional} describing the first element of this list
* that matches the given predicate, or an empty {@code Optional} if no such
* element is found.
*
* @param elements the list of elements to search for a
* matching element
* @param predicate the predicate to apply to each element in
* the list
* @param the type of the elements in the list
* @return an {@code Optional} describing the first
* matching element, or an empty
* {@code Optional} if no such element is found
* @throws NullPointerException if the specified list or predicate is null
*/
public Optional findFirst(List elements, Predicate predicate) {
return elements.parallelStream()
.filter(predicate)
.findFirst();
}
/**
* It returns an IntStream of the indices of the elements in the given list.
*
* @param elements The list of elements to iterate over.
* @return An IntStream of the indexes of the elements in the list.
*/
public IntStream of(List elements) {
return of(0, elements.size());
}
/**
* Returns an IntStream of the numbers between start and end, inclusive.
*
* @param start The starting value of the range.
* @param end The end value (exclusive) for the range to be created
* @return IntStream
*/
public IntStream of(int start, int end) {
return IntStream.range(start, end);
}
/**
* Merges two lists by applying a specified function to corresponding
* elements of the two lists. The resulting stream contains the results of
* these function applications in order. The length of the resulting stream
* is equal to the length of the shorter of the two input lists.
*
* @param first the first list to be zipped
* @param second the second list to be zipped
* @param zipper a function that combines the elements of the two lists
* @param the type of elements in the first list
* @param the type of elements in the second list
* @param the type of elements in the resulting stream
* @return a stream of the results of applying the given function to
* corresponding elements of the two lists
*/
public static Stream zip(List first, List second, BiFunction zipper) {
return IntStream.range(0, Math.min(first.size(), second.size()))
.mapToObj(i -> {
var firstValue = i < first.size() ? first.get(i) : null;
var secondValue = i < second.size() ? second.get(i) : null;
return zipper.apply(firstValue, secondValue);
});
}
/**
* Converts a list of lists of values into a {@link DataTable}, using the
* first row as headers.
*
* This method transforms a nested list structure into a structured
* {@link DataTable}, facilitating data manipulation and analysis with
* tabular data. It handles missing values gracefully by using empty strings
* as defaults.
*
* @param cells the list of lists of values to convert
* @return the resulting {@code DataTable}
*/
public DataTable toTable(List extends List> cells) {
var headers = Lists.toString(cells.get(0));
return cells.stream()
.skip(1)
.map(row -> Maps.of(headers, Lists.toString(row), ""))
.collect(Collectors.toCollection(DataTable::new));
}
/**
* Converts a List of Maps into a Map of Lists, where keys from the input
* Maps are grouped together, and their corresponding values are aggregated
* into Lists.
*
* @param listMap A List of Maps to be converted into a Map of Lists.
* @return A Map of Lists where each key is mapped to a List of
* values from the input List.
*/
public Map> toMapOfList(List