Java tutorial
/* * 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 * * 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 org.apache.calcite.linq4j; import org.apache.calcite.linq4j.function.BigDecimalFunction1; import org.apache.calcite.linq4j.function.DoubleFunction1; import org.apache.calcite.linq4j.function.EqualityComparer; import org.apache.calcite.linq4j.function.FloatFunction1; import org.apache.calcite.linq4j.function.Function0; import org.apache.calcite.linq4j.function.Function1; import org.apache.calcite.linq4j.function.Function2; import org.apache.calcite.linq4j.function.Functions; import org.apache.calcite.linq4j.function.IntegerFunction1; import org.apache.calcite.linq4j.function.LongFunction1; import org.apache.calcite.linq4j.function.NullableBigDecimalFunction1; import org.apache.calcite.linq4j.function.NullableDoubleFunction1; import org.apache.calcite.linq4j.function.NullableFloatFunction1; import org.apache.calcite.linq4j.function.NullableIntegerFunction1; import org.apache.calcite.linq4j.function.NullableLongFunction1; import org.apache.calcite.linq4j.function.Predicate1; import org.apache.calcite.linq4j.function.Predicate2; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.math.BigDecimal; import java.util.AbstractList; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.RandomAccess; import java.util.Set; import java.util.TreeMap; import static org.apache.calcite.linq4j.Linq4j.CollectionEnumerable; import static org.apache.calcite.linq4j.Linq4j.ListEnumerable; import static org.apache.calcite.linq4j.function.Functions.adapt; /** * Default implementations of methods in the {@link Enumerable} interface. */ public abstract class EnumerableDefaults { /** * Applies an accumulator function over a sequence. */ public static <TSource> TSource aggregate(Enumerable<TSource> source, Function2<TSource, TSource, TSource> func) { TSource result = null; try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); result = func.apply(result, o); } return result; } } /** * Applies an accumulator function over a * sequence. The specified seed value is used as the initial * accumulator value. */ public static <TSource, TAccumulate> TAccumulate aggregate(Enumerable<TSource> source, TAccumulate seed, Function2<TAccumulate, TSource, TAccumulate> func) { TAccumulate result = seed; try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); result = func.apply(result, o); } return result; } } /** * Applies an accumulator function over a * sequence. The specified seed value is used as the initial * accumulator value, and the specified function is used to select * the result value. */ public static <TSource, TAccumulate, TResult> TResult aggregate(Enumerable<TSource> source, TAccumulate seed, Function2<TAccumulate, TSource, TAccumulate> func, Function1<TAccumulate, TResult> selector) { TAccumulate accumulate = seed; try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); accumulate = func.apply(accumulate, o); } return selector.apply(accumulate); } } /** * Determines whether all elements of a sequence * satisfy a condition. */ public static <TSource> boolean all(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); if (!predicate.apply(o)) { return false; } } return true; } } /** * Determines whether a sequence contains any * elements. */ public static boolean any(Enumerable enumerable) { return enumerable.enumerator().moveNext(); } /** * Determines whether any element of a sequence * satisfies a condition. */ public static <TSource> boolean any(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); if (predicate.apply(o)) { return true; } } return false; } } /** * Returns the input typed as {@code Enumerable<TSource>}. * * <p>This method has no effect other than to change the compile-time type of * source from a type that implements {@code Enumerable<TSource>} to * {@code Enumerable<TSource>} itself. * * <p>{@code AsEnumerable<TSource>(Enumerable<TSource>)} can be used to choose * between query implementations when a sequence implements * {@code Enumerable<TSource>} but also has a different set of public query * methods available. For example, given a generic class {@code Table} that * implements {@code Enumerable<TSource>} and has its own methods such as * {@code where}, {@code select}, and {@code selectMany}, a call to * {@code where} would invoke the public {@code where} method of * {@code Table}. A {@code Table} type that represents a database table could * have a {@code where} method that takes the predicate argument as an * expression tree and converts the tree to SQL for remote execution. If * remote execution is not desired, for example because the predicate invokes * a local method, the {@code asEnumerable<TSource>} method can be used to * hide the custom methods and instead make the standard query operators * available. */ public static <TSource> Enumerable<TSource> asEnumerable(Enumerable<TSource> enumerable) { return enumerable; } /** * Converts an Enumerable to an IQueryable. * * <p>Analogous to the LINQ's Enumerable.AsQueryable extension method.</p> * * @param enumerable Enumerable * @param <TSource> Element type * * @return A queryable */ public static <TSource> Queryable<TSource> asQueryable(Enumerable<TSource> enumerable) { throw Extensions.todo(); } /** * Computes the average of a sequence of Decimal * values that are obtained by invoking a transform function on * each element of the input sequence. */ public static <TSource> BigDecimal average(Enumerable<TSource> source, BigDecimalFunction1<TSource> selector) { return sum(source, selector).divide(BigDecimal.valueOf(longCount(source))); } /** * Computes the average of a sequence of nullable * Decimal values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> BigDecimal average(Enumerable<TSource> source, NullableBigDecimalFunction1<TSource> selector) { return sum(source, selector).divide(BigDecimal.valueOf(longCount(source))); } /** * Computes the average of a sequence of Double * values that are obtained by invoking a transform function on * each element of the input sequence. */ public static <TSource> double average(Enumerable<TSource> source, DoubleFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * Computes the average of a sequence of nullable * Double values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> Double average(Enumerable<TSource> source, NullableDoubleFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * Computes the average of a sequence of int values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> int average(Enumerable<TSource> source, IntegerFunction1<TSource> selector) { return sum(source, selector) / count(source); } /** * Computes the average of a sequence of nullable * int values that are obtained by invoking a transform function * on each element of the input sequence. */ public static <TSource> Integer average(Enumerable<TSource> source, NullableIntegerFunction1<TSource> selector) { return sum(source, selector) / count(source); } /** * Computes the average of a sequence of long values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> long average(Enumerable<TSource> source, LongFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * Computes the average of a sequence of nullable * long values that are obtained by invoking a transform function * on each element of the input sequence. */ public static <TSource> Long average(Enumerable<TSource> source, NullableLongFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * Computes the average of a sequence of Float * values that are obtained by invoking a transform function on * each element of the input sequence. */ public static <TSource> float average(Enumerable<TSource> source, FloatFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * Computes the average of a sequence of nullable * Float values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> Float average(Enumerable<TSource> source, NullableFloatFunction1<TSource> selector) { return sum(source, selector) / longCount(source); } /** * <p>Analogous to LINQ's Enumerable.Cast extension method.</p> * * @param clazz Target type * @param <T2> Target type * * @return Collection of T2 */ public static <TSource, T2> Enumerable<T2> cast(final Enumerable<TSource> source, final Class<T2> clazz) { return new AbstractEnumerable<T2>() { public Enumerator<T2> enumerator() { return new CastingEnumerator<>(source.enumerator(), clazz); } }; } /** * Concatenates two sequences. */ public static <TSource> Enumerable<TSource> concat(Enumerable<TSource> enumerable0, Enumerable<TSource> enumerable1) { //noinspection unchecked return Linq4j.concat(Arrays.asList(enumerable0, enumerable1)); } /** * Determines whether a sequence contains a specified * element by using the default equality comparer. */ public static <TSource> boolean contains(Enumerable<TSource> enumerable, TSource element) { // Implementations of Enumerable backed by a Collection call // Collection.contains, which may be more efficient, not this method. try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); if (o.equals(element)) { return true; } } return false; } } /** * Determines whether a sequence contains a specified * element by using a specified {@code EqualityComparer<TSource>}. */ public static <TSource> boolean contains(Enumerable<TSource> enumerable, TSource element, EqualityComparer<TSource> comparer) { for (TSource o : enumerable) { if (comparer.equal(o, element)) { return true; } } return false; } /** * Returns the number of elements in a * sequence. */ public static <TSource> int count(Enumerable<TSource> enumerable) { return (int) longCount(enumerable, Functions.<TSource>truePredicate1()); } /** * Returns a number that represents how many elements * in the specified sequence satisfy a condition. */ public static <TSource> int count(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { return (int) longCount(enumerable, predicate); } /** * Returns the elements of the specified sequence or * the type parameter's default value in a singleton collection if * the sequence is empty. */ public static <TSource> Enumerable<TSource> defaultIfEmpty(Enumerable<TSource> enumerable) { return defaultIfEmpty(enumerable, null); } /** * Returns the elements of the specified sequence or * the specified value in a singleton collection if the sequence * is empty. */ public static <TSource> Enumerable<TSource> defaultIfEmpty(Enumerable<TSource> enumerable, TSource value) { try (Enumerator<TSource> os = enumerable.enumerator()) { if (os.moveNext()) { return Linq4j.asEnumerable(new Iterable<TSource>() { public Iterator<TSource> iterator() { return new Iterator<TSource>() { private boolean nonFirst; private Iterator<TSource> rest; public boolean hasNext() { return !nonFirst || rest.hasNext(); } public TSource next() { if (nonFirst) { return rest.next(); } else { final TSource first = os.current(); nonFirst = true; rest = Linq4j.enumeratorIterator(os); return first; } } public void remove() { throw new UnsupportedOperationException("remove"); } }; } }); } else { return Linq4j.singletonEnumerable(value); } } } /** * Returns distinct elements from a sequence by using * the default {@link EqualityComparer} to compare values. */ public static <TSource> Enumerable<TSource> distinct(Enumerable<TSource> enumerable) { final Enumerator<TSource> os = enumerable.enumerator(); final Set<TSource> set = new HashSet<>(); while (os.moveNext()) { set.add(os.current()); } os.close(); return Linq4j.asEnumerable(set); } /** * Returns distinct elements from a sequence by using * a specified {@link EqualityComparer} to compare values. */ public static <TSource> Enumerable<TSource> distinct(Enumerable<TSource> enumerable, EqualityComparer<TSource> comparer) { if (comparer == Functions.identityComparer()) { return distinct(enumerable); } final Set<Wrapped<TSource>> set = new HashSet<>(); Function1<TSource, Wrapped<TSource>> wrapper = wrapperFor(comparer); Function1<Wrapped<TSource>, TSource> unwrapper = unwrapper(); enumerable.select(wrapper).into(set); return Linq4j.asEnumerable(set).select(unwrapper); } /** * Returns the element at a specified index in a * sequence. */ public static <TSource> TSource elementAt(Enumerable<TSource> enumerable, int index) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (list != null) { return list.toList().get(index); } if (index < 0) { throw new IndexOutOfBoundsException(); } try (Enumerator<TSource> os = enumerable.enumerator()) { while (true) { if (!os.moveNext()) { throw new IndexOutOfBoundsException(); } if (index == 0) { return os.current(); } index--; } } } /** * Returns the element at a specified index in a * sequence or a default value if the index is out of * range. */ public static <TSource> TSource elementAtOrDefault(Enumerable<TSource> enumerable, int index) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (index >= 0) { if (list != null) { final List<TSource> rawList = list.toList(); if (index < rawList.size()) { return rawList.get(index); } } else { try (Enumerator<TSource> os = enumerable.enumerator()) { while (true) { if (!os.moveNext()) { break; } if (index == 0) { return os.current(); } index--; } } } } return null; } /** * Produces the set difference of two sequences by * using the default equality comparer to compare values. (Defined * by Enumerable.) */ public static <TSource> Enumerable<TSource> except(Enumerable<TSource> source0, Enumerable<TSource> source1) { Set<TSource> set = new HashSet<>(); source0.into(set); try (Enumerator<TSource> os = source1.enumerator()) { while (os.moveNext()) { TSource o = os.current(); set.remove(o); } return Linq4j.asEnumerable(set); } } /** * Produces the set difference of two sequences by * using the specified {@code EqualityComparer<TSource>} to compare * values. */ public static <TSource> Enumerable<TSource> except(Enumerable<TSource> source0, Enumerable<TSource> source1, EqualityComparer<TSource> comparer) { if (comparer == Functions.identityComparer()) { return except(source0, source1); } Set<Wrapped<TSource>> set = new HashSet<>(); Function1<TSource, Wrapped<TSource>> wrapper = wrapperFor(comparer); source0.select(wrapper).into(set); try (Enumerator<Wrapped<TSource>> os = source1.select(wrapper).enumerator()) { while (os.moveNext()) { Wrapped<TSource> o = os.current(); set.remove(o); } } Function1<Wrapped<TSource>, TSource> unwrapper = unwrapper(); return Linq4j.asEnumerable(set).select(unwrapper); } /** * Returns the first element of a sequence. (Defined * by Enumerable.) */ public static <TSource> TSource first(Enumerable<TSource> enumerable) { try (Enumerator<TSource> os = enumerable.enumerator()) { if (os.moveNext()) { return os.current(); } throw new NoSuchElementException(); } } /** * Returns the first element in a sequence that * satisfies a specified condition. */ public static <TSource> TSource first(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { for (TSource o : enumerable) { if (predicate.apply(o)) { return o; } } throw new NoSuchElementException(); } /** * Returns the first element of a sequence, or a * default value if the sequence contains no elements. */ public static <TSource> TSource firstOrDefault(Enumerable<TSource> enumerable) { try (Enumerator<TSource> os = enumerable.enumerator()) { if (os.moveNext()) { return os.current(); } return null; } } /** * Returns the first element of the sequence that * satisfies a condition or a default value if no such element is * found. */ public static <TSource> TSource firstOrDefault(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { for (TSource o : enumerable) { if (predicate.apply(o)) { return o; } } return null; } /** * Groups the elements of a sequence according to a * specified key selector function. */ public static <TSource, TKey> Enumerable<Grouping<TKey, TSource>> groupBy(final Enumerable<TSource> enumerable, final Function1<TSource, TKey> keySelector) { return enumerable.toLookup(keySelector); } /** * Groups the elements of a sequence according to a * specified key selector function and compares the keys by using * a specified comparer. */ public static <TSource, TKey> Enumerable<Grouping<TKey, TSource>> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, EqualityComparer<TKey> comparer) { return enumerable.toLookup(keySelector, comparer); } /** * Groups the elements of a sequence according to a * specified key selector function and projects the elements for * each group by using a specified function. */ public static <TSource, TKey, TElement> Enumerable<Grouping<TKey, TElement>> groupBy( Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector) { return enumerable.toLookup(keySelector, elementSelector); } /** * Groups the elements of a sequence according to a * key selector function. The keys are compared by using a * comparer and each group's elements are projected by using a * specified function. */ public static <TSource, TKey, TElement> Enumerable<Grouping<TKey, TElement>> groupBy( Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector, EqualityComparer<TKey> comparer) { return enumerable.toLookup(keySelector, elementSelector, comparer); } /** * Groups the elements of a sequence according to a * specified key selector function and creates a result value from * each group and its key. */ public static <TSource, TKey, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, final Function2<TKey, Enumerable<TSource>, TResult> resultSelector) { return enumerable.toLookup(keySelector).select(new Function1<Grouping<TKey, TSource>, TResult>() { public TResult apply(Grouping<TKey, TSource> group) { return resultSelector.apply(group.getKey(), group); } }); } /** * Groups the elements of a sequence according to a * specified key selector function and creates a result value from * each group and its key. The keys are compared by using a * specified comparer. */ public static <TSource, TKey, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, final Function2<TKey, Enumerable<TSource>, TResult> resultSelector, EqualityComparer<TKey> comparer) { return enumerable.toLookup(keySelector, comparer).select(new Function1<Grouping<TKey, TSource>, TResult>() { public TResult apply(Grouping<TKey, TSource> group) { return resultSelector.apply(group.getKey(), group); } }); } /** * Groups the elements of a sequence according to a * specified key selector function and creates a result value from * each group and its key. The elements of each group are * projected by using a specified function. */ public static <TSource, TKey, TElement, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector, final Function2<TKey, Enumerable<TElement>, TResult> resultSelector) { return enumerable.toLookup(keySelector, elementSelector) .select(new Function1<Grouping<TKey, TElement>, TResult>() { public TResult apply(Grouping<TKey, TElement> group) { return resultSelector.apply(group.getKey(), group); } }); } /** * Groups the elements of a sequence according to a * specified key selector function and creates a result value from * each group and its key. Key values are compared by using a * specified comparer, and the elements of each group are * projected by using a specified function. */ public static <TSource, TKey, TElement, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector, final Function2<TKey, Enumerable<TElement>, TResult> resultSelector, EqualityComparer<TKey> comparer) { return enumerable.toLookup(keySelector, elementSelector, comparer) .select(new Function1<Grouping<TKey, TElement>, TResult>() { public TResult apply(Grouping<TKey, TElement> group) { return resultSelector.apply(group.getKey(), group); } }); } /** * Groups the elements of a sequence according to a * specified key selector function, initializing an accumulator for each * group and adding to it each time an element with the same key is seen. * Creates a result value from each accumulator and its key using a * specified function. */ public static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function0<TAccumulate> accumulatorInitializer, Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder, final Function2<TKey, TAccumulate, TResult> resultSelector) { return groupBy_(new HashMap<TKey, TAccumulate>(), enumerable, keySelector, accumulatorInitializer, accumulatorAdder, resultSelector); } /** * Groups the elements of a sequence according to a list of * specified key selector functions, initializing an accumulator for each * group and adding to it each time an element with the same key is seen. * Creates a result value from each accumulator and its key using a * specified function. * * <p>This method exists to support SQL {@code GROUPING SETS}. * It does not correspond to any method in {@link Enumerable}. */ public static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult> groupByMultiple( Enumerable<TSource> enumerable, List<Function1<TSource, TKey>> keySelectors, Function0<TAccumulate> accumulatorInitializer, Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder, final Function2<TKey, TAccumulate, TResult> resultSelector) { return groupByMultiple_(new HashMap<TKey, TAccumulate>(), enumerable, keySelectors, accumulatorInitializer, accumulatorAdder, resultSelector); } /** * Groups the elements of a sequence according to a * specified key selector function, initializing an accumulator for each * group and adding to it each time an element with the same key is seen. * Creates a result value from each accumulator and its key using a * specified function. Key values are compared by using a * specified comparer. */ public static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult> groupBy(Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function0<TAccumulate> accumulatorInitializer, Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder, Function2<TKey, TAccumulate, TResult> resultSelector, EqualityComparer<TKey> comparer) { return groupBy_(new WrapMap<>(new Function0<Map<Wrapped<TKey>, TAccumulate>>() { public Map<Wrapped<TKey>, TAccumulate> apply() { return new HashMap<>(); } }, comparer), enumerable, keySelector, accumulatorInitializer, accumulatorAdder, resultSelector); } private static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult> groupBy_( final Map<TKey, TAccumulate> map, Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, Function0<TAccumulate> accumulatorInitializer, Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder, final Function2<TKey, TAccumulate, TResult> resultSelector) { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); TKey key = keySelector.apply(o); TAccumulate accumulator = map.get(key); if (accumulator == null) { accumulator = accumulatorInitializer.apply(); accumulator = accumulatorAdder.apply(accumulator, o); map.put(key, accumulator); } else { TAccumulate accumulator0 = accumulator; accumulator = accumulatorAdder.apply(accumulator, o); if (accumulator != accumulator0) { map.put(key, accumulator); } } } } return new LookupResultEnumerable<>(map, resultSelector); } private static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult> groupByMultiple_( final Map<TKey, TAccumulate> map, Enumerable<TSource> enumerable, List<Function1<TSource, TKey>> keySelectors, Function0<TAccumulate> accumulatorInitializer, Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder, final Function2<TKey, TAccumulate, TResult> resultSelector) { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { for (Function1<TSource, TKey> keySelector : keySelectors) { TSource o = os.current(); TKey key = keySelector.apply(o); TAccumulate accumulator = map.get(key); if (accumulator == null) { accumulator = accumulatorInitializer.apply(); accumulator = accumulatorAdder.apply(accumulator, o); map.put(key, accumulator); } else { TAccumulate accumulator0 = accumulator; accumulator = accumulatorAdder.apply(accumulator, o); if (accumulator != accumulator0) { map.put(key, accumulator); } } } } } return new LookupResultEnumerable<>(map, resultSelector); } private static <TSource, TKey, TResult> Enumerable<TResult> groupBy_(final Set<TKey> map, Enumerable<TSource> enumerable, Function1<TSource, TKey> keySelector, final Function1<TKey, TResult> resultSelector) { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); TKey key = keySelector.apply(o); map.add(key); } } return Linq4j.asEnumerable(map).select(resultSelector); } /** * Correlates the elements of two sequences based on * equality of keys and groups the results. The default equality * comparer is used to compare keys. */ public static <TSource, TInner, TKey, TResult> Enumerable<TResult> groupJoin(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final Function2<TSource, Enumerable<TInner>, TResult> resultSelector) { return new AbstractEnumerable<TResult>() { final Map<TKey, TSource> outerMap = outer.toMap(outerKeySelector); final Lookup<TKey, TInner> innerLookup = inner.toLookup(innerKeySelector); final Enumerator<Map.Entry<TKey, TSource>> entries = Linq4j.enumerator(outerMap.entrySet()); public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { public TResult current() { final Map.Entry<TKey, TSource> entry = entries.current(); final Enumerable<TInner> inners = innerLookup.get(entry.getKey()); return resultSelector.apply(entry.getValue(), inners == null ? Linq4j.<TInner>emptyEnumerable() : inners); } public boolean moveNext() { return entries.moveNext(); } public void reset() { entries.reset(); } public void close() { } }; } }; } /** * Correlates the elements of two sequences based on * key equality and groups the results. A specified * {@code EqualityComparer<TSource>} is used to compare keys. */ public static <TSource, TInner, TKey, TResult> Enumerable<TResult> groupJoin(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final Function2<TSource, Enumerable<TInner>, TResult> resultSelector, final EqualityComparer<TKey> comparer) { return new AbstractEnumerable<TResult>() { final Map<TKey, TSource> outerMap = outer.toMap(outerKeySelector, comparer); final Lookup<TKey, TInner> innerLookup = inner.toLookup(innerKeySelector, comparer); final Enumerator<Map.Entry<TKey, TSource>> entries = Linq4j.enumerator(outerMap.entrySet()); public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { public TResult current() { final Map.Entry<TKey, TSource> entry = entries.current(); final Enumerable<TInner> inners = innerLookup.get(entry.getKey()); return resultSelector.apply(entry.getValue(), inners == null ? Linq4j.<TInner>emptyEnumerable() : inners); } public boolean moveNext() { return entries.moveNext(); } public void reset() { entries.reset(); } public void close() { } }; } }; } /** * Produces the set intersection of two sequences by * using the default equality comparer to compare values. (Defined * by Enumerable.) */ public static <TSource> Enumerable<TSource> intersect(Enumerable<TSource> source0, Enumerable<TSource> source1) { Set<TSource> set0 = new HashSet<>(); source0.into(set0); Set<TSource> set1 = new HashSet<>(); try (Enumerator<TSource> os = source1.enumerator()) { while (os.moveNext()) { TSource o = os.current(); if (set0.contains(o)) { set1.add(o); } } } return Linq4j.asEnumerable(set1); } /** * Produces the set intersection of two sequences by * using the specified {@code EqualityComparer<TSource>} to compare * values. */ public static <TSource> Enumerable<TSource> intersect(Enumerable<TSource> source0, Enumerable<TSource> source1, EqualityComparer<TSource> comparer) { if (comparer == Functions.identityComparer()) { return intersect(source0, source1); } Set<Wrapped<TSource>> set0 = new HashSet<>(); Function1<TSource, Wrapped<TSource>> wrapper = wrapperFor(comparer); source0.select(wrapper).into(set0); Set<Wrapped<TSource>> set1 = new HashSet<>(); try (Enumerator<Wrapped<TSource>> os = source1.select(wrapper).enumerator()) { while (os.moveNext()) { Wrapped<TSource> o = os.current(); if (set0.contains(o)) { set1.add(o); } } } Function1<Wrapped<TSource>, TSource> unwrapper = unwrapper(); return Linq4j.asEnumerable(set1).select(unwrapper); } /** * Correlates the elements of two sequences based on * matching keys. The default equality comparer is used to compare * keys. */ public static <TSource, TInner, TKey, TResult> Enumerable<TResult> join(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final Function2<TSource, TInner, TResult> resultSelector) { return join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null, false, false); } /** * Correlates the elements of two sequences based on * matching keys. A specified {@code EqualityComparer<TSource>} is used to * compare keys. */ public static <TSource, TInner, TKey, TResult> Enumerable<TResult> join(Enumerable<TSource> outer, Enumerable<TInner> inner, Function1<TSource, TKey> outerKeySelector, Function1<TInner, TKey> innerKeySelector, Function2<TSource, TInner, TResult> resultSelector, EqualityComparer<TKey> comparer) { return join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, false, false); } /** * Correlates the elements of two sequences based on * matching keys. A specified {@code EqualityComparer<TSource>} is used to * compare keys. */ public static <TSource, TInner, TKey, TResult> Enumerable<TResult> join(Enumerable<TSource> outer, Enumerable<TInner> inner, Function1<TSource, TKey> outerKeySelector, Function1<TInner, TKey> innerKeySelector, Function2<TSource, TInner, TResult> resultSelector, EqualityComparer<TKey> comparer, boolean generateNullsOnLeft, boolean generateNullsOnRight) { return join_(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, generateNullsOnLeft, generateNullsOnRight); } /** Implementation of join that builds the right input and probes with the * left. */ private static <TSource, TInner, TKey, TResult> Enumerable<TResult> join_(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final Function2<TSource, TInner, TResult> resultSelector, final EqualityComparer<TKey> comparer, final boolean generateNullsOnLeft, final boolean generateNullsOnRight) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { final Lookup<TKey, TInner> innerLookup = comparer == null ? inner.toLookup(innerKeySelector) : inner.toLookup(innerKeySelector, comparer); return new Enumerator<TResult>() { Enumerator<TSource> outers = outer.enumerator(); Enumerator<TInner> inners = Linq4j.emptyEnumerator(); Set<TKey> unmatchedKeys = generateNullsOnLeft ? new HashSet<>(innerLookup.keySet()) : null; public TResult current() { return resultSelector.apply(outers.current(), inners.current()); } public boolean moveNext() { for (;;) { if (inners.moveNext()) { return true; } if (!outers.moveNext()) { if (unmatchedKeys != null) { // We've seen everything else. If we are doing a RIGHT or FULL // join (leftNull = true) there are any keys which right but // not the left. List<TInner> list = new ArrayList<>(); for (TKey key : unmatchedKeys) { for (TInner tInner : innerLookup.get(key)) { list.add(tInner); } } inners = Linq4j.enumerator(list); outers = Linq4j.singletonNullEnumerator(); outers.moveNext(); unmatchedKeys = null; // don't do the 'leftovers' again continue; } return false; } final TSource outer = outers.current(); final Enumerable<TInner> innerEnumerable; if (outer == null) { innerEnumerable = null; } else { final TKey outerKey = outerKeySelector.apply(outer); if (outerKey == null) { innerEnumerable = null; } else { if (unmatchedKeys != null) { unmatchedKeys.remove(outerKey); } innerEnumerable = innerLookup.get(outerKey); } } if (innerEnumerable == null || !innerEnumerable.any()) { if (generateNullsOnRight) { inners = Linq4j.singletonNullEnumerator(); } else { inners = Linq4j.emptyEnumerator(); } } else { inners = innerEnumerable.enumerator(); } } } public void reset() { outers.reset(); } public void close() { outers.close(); } }; } }; } /** * Returns elements of {@code outer} for which there is a member of * {@code inner} with a matching key. A specified * {@code EqualityComparer<TSource>} is used to compare keys. */ public static <TSource, TInner, TResult> Enumerable<TResult> correlateJoin(final CorrelateJoinType joinType, final Enumerable<TSource> outer, final Function1<TSource, Enumerable<TInner>> inner, final Function2<TSource, TInner, TResult> resultSelector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { private Enumerator<TSource> outerEnumerator = outer.enumerator(); private Enumerator<TInner> innerEnumerator; TSource outerValue; TInner innerValue; int state = 0; // 0 -- moving outer, 1 moving inner; public TResult current() { return resultSelector.apply(outerValue, innerValue); } public boolean moveNext() { while (true) { switch (state) { case 0: // move outer if (!outerEnumerator.moveNext()) { return false; } outerValue = outerEnumerator.current(); // initial move inner Enumerable<TInner> innerEnumerable = inner.apply(outerValue); if (innerEnumerable == null) { innerEnumerable = Linq4j.emptyEnumerable(); } if (innerEnumerator != null) { innerEnumerator.close(); } innerEnumerator = innerEnumerable.enumerator(); if (innerEnumerator.moveNext()) { switch (joinType) { case ANTI: // For anti-join need to try next outer row // Current does not match continue; case SEMI: return true; // current row matches } // INNER and LEFT just return result innerValue = innerEnumerator.current(); state = 1; // iterate over inner results return true; } // No match detected innerValue = null; switch (joinType) { case LEFT: case ANTI: return true; } // For INNER and LEFT need to find another outer row continue; case 1: // subsequent move inner if (innerEnumerator.moveNext()) { innerValue = innerEnumerator.current(); return true; } state = 0; // continue loop, move outer } } } public void reset() { state = 0; outerEnumerator.reset(); closeInner(); } public void close() { outerEnumerator.close(); closeInner(); outerValue = null; } private void closeInner() { innerValue = null; if (innerEnumerator != null) { innerEnumerator.close(); innerEnumerator = null; } } }; } }; } /** * Returns the last element of a sequence. (Defined * by Enumerable.) */ public static <TSource> TSource last(Enumerable<TSource> enumerable) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (list != null) { final List<TSource> rawList = list.toList(); final int count = rawList.size(); if (count > 0) { return rawList.get(count - 1); } } else { try (Enumerator<TSource> os = enumerable.enumerator()) { if (os.moveNext()) { TSource result; do { result = os.current(); } while (os.moveNext()); return result; } } } throw new NoSuchElementException(); } /** * Returns elements of {@code outer} for which there is a member of * {@code inner} with a matching key. */ public static <TSource, TInner, TKey> Enumerable<TSource> semiJoin(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector) { return semiJoin(outer, inner, outerKeySelector, innerKeySelector, null); } /** * Returns elements of {@code outer} for which there is a member of * {@code inner} with a matching key. A specified * {@code EqualityComparer<TSource>} is used to compare keys. */ public static <TSource, TInner, TKey> Enumerable<TSource> semiJoin(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final EqualityComparer<TKey> comparer) { return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { final Enumerable<TKey> innerLookup = comparer == null ? inner.select(innerKeySelector).distinct() : inner.select(innerKeySelector).distinct(comparer); return EnumerableDefaults.where(outer.enumerator(), new Predicate1<TSource>() { public boolean apply(TSource v0) { final TKey key = outerKeySelector.apply(v0); return innerLookup.contains(key); } }); } }; } /** * Correlates the elements of two sequences based on a predicate. */ public static <TSource, TInner, TResult> Enumerable<TResult> thetaJoin(final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Predicate2<TSource, TInner> predicate, Function2<TSource, TInner, TResult> resultSelector, final boolean generateNullsOnLeft, final boolean generateNullsOnRight) { // Building the result as a list is easy but hogs memory. We should iterate. final List<TResult> result = Lists.newArrayList(); final Enumerator<TSource> lefts = outer.enumerator(); final List<TInner> rightList = inner.toList(); final Set<TInner> rightUnmatched; if (generateNullsOnLeft) { rightUnmatched = Sets.newIdentityHashSet(); rightUnmatched.addAll(rightList); } else { rightUnmatched = null; } while (lefts.moveNext()) { int leftMatchCount = 0; final TSource left = lefts.current(); final Enumerator<TInner> rights = Linq4j.iterableEnumerator(rightList); while (rights.moveNext()) { TInner right = rights.current(); if (predicate.apply(left, right)) { ++leftMatchCount; if (rightUnmatched != null) { rightUnmatched.remove(right); } result.add(resultSelector.apply(left, right)); } } if (generateNullsOnRight && leftMatchCount == 0) { result.add(resultSelector.apply(left, null)); } } if (rightUnmatched != null) { final Enumerator<TInner> rights = Linq4j.iterableEnumerator(rightUnmatched); while (rights.moveNext()) { TInner right = rights.current(); result.add(resultSelector.apply(null, right)); } } return Linq4j.asEnumerable(result); } /** Joins two inputs that are sorted on the key. */ public static <TSource, TInner, TKey extends Comparable<TKey>, TResult> Enumerable<TResult> mergeJoin( final Enumerable<TSource> outer, final Enumerable<TInner> inner, final Function1<TSource, TKey> outerKeySelector, final Function1<TInner, TKey> innerKeySelector, final Function2<TSource, TInner, TResult> resultSelector, boolean generateNullsOnLeft, boolean generateNullsOnRight) { assert !generateNullsOnLeft : "not implemented"; assert !generateNullsOnRight : "not implemented"; return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new MergeJoinEnumerator<>(outer.enumerator(), inner.enumerator(), outerKeySelector, innerKeySelector, resultSelector); } }; } /** * Returns the last element of a sequence that * satisfies a specified condition. */ public static <TSource> TSource last(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (list != null) { final List<TSource> rawList = list.toList(); final int count = rawList.size(); for (int i = count - 1; i >= 0; --i) { TSource result = rawList.get(i); if (predicate.apply(result)) { return result; } } } else { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource result = os.current(); if (predicate.apply(result)) { while (os.moveNext()) { TSource element = os.current(); if (predicate.apply(element)) { result = element; } } return result; } } } } throw new NoSuchElementException(); } /** * Returns the last element of a sequence, or a * default value if the sequence contains no elements. */ public static <TSource> TSource lastOrDefault(Enumerable<TSource> enumerable) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (list != null) { final List<TSource> rawList = list.toList(); final int count = rawList.size(); if (count > 0) { return rawList.get(count - 1); } } else { try (Enumerator<TSource> os = enumerable.enumerator()) { if (os.moveNext()) { TSource result; do { result = os.current(); } while (os.moveNext()); return result; } } } return null; } /** * Returns the last element of a sequence that * satisfies a condition or a default value if no such element is * found. */ public static <TSource> TSource lastOrDefault(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { final ListEnumerable<TSource> list = enumerable instanceof ListEnumerable ? ((ListEnumerable<TSource>) enumerable) : null; if (list != null) { final List<TSource> rawList = list.toList(); final int count = rawList.size(); for (int i = count - 1; i >= 0; --i) { TSource result = rawList.get(i); if (predicate.apply(result)) { return result; } } } else { try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource result = os.current(); if (predicate.apply(result)) { while (os.moveNext()) { TSource element = os.current(); if (predicate.apply(element)) { result = element; } } return result; } } } } return null; } /** * Returns an long that represents the total number * of elements in a sequence. */ public static <TSource> long longCount(Enumerable<TSource> source) { return longCount(source, Functions.<TSource>truePredicate1()); } /** * Returns an long that represents how many elements * in a sequence satisfy a condition. */ public static <TSource> long longCount(Enumerable<TSource> enumerable, Predicate1<TSource> predicate) { // Shortcut if this is a collection and the predicate is always true. if (predicate == Predicate1.TRUE && enumerable instanceof Collection) { return ((Collection) enumerable).size(); } int n = 0; try (Enumerator<TSource> os = enumerable.enumerator()) { while (os.moveNext()) { TSource o = os.current(); if (predicate.apply(o)) { ++n; } } } return n; } /** * Returns the maximum value in a generic * sequence. */ public static <TSource extends Comparable<TSource>> TSource max(Enumerable<TSource> source) { Function2<TSource, TSource, TSource> max = maxFunction(); return aggregate(source, null, max); } /** * Invokes a transform function on each element of a * sequence and returns the maximum Decimal value. */ public static <TSource> BigDecimal max(Enumerable<TSource> source, BigDecimalFunction1<TSource> selector) { Function2<BigDecimal, BigDecimal, BigDecimal> max = maxFunction(); return aggregate(source.select(selector), null, max); } /** * Invokes a transform function on each element of a * sequence and returns the maximum nullable Decimal * value. */ public static <TSource> BigDecimal max(Enumerable<TSource> source, NullableBigDecimalFunction1<TSource> selector) { Function2<BigDecimal, BigDecimal, BigDecimal> max = maxFunction(); return aggregate(source.select(selector), null, max); } /** * Invokes a transform function on each element of a * sequence and returns the maximum Double value. */ public static <TSource> double max(Enumerable<TSource> source, DoubleFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.DOUBLE_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum nullable Double * value. */ public static <TSource> Double max(Enumerable<TSource> source, NullableDoubleFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.DOUBLE_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum int value. */ public static <TSource> int max(Enumerable<TSource> source, IntegerFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.INTEGER_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum nullable int value. (Defined * by Enumerable.) */ public static <TSource> Integer max(Enumerable<TSource> source, NullableIntegerFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.INTEGER_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum long value. */ public static <TSource> long max(Enumerable<TSource> source, LongFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.LONG_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum nullable long value. (Defined * by Enumerable.) */ public static <TSource> Long max(Enumerable<TSource> source, NullableLongFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.LONG_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum Float value. */ public static <TSource> float max(Enumerable<TSource> source, FloatFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.FLOAT_MAX); } /** * Invokes a transform function on each element of a * sequence and returns the maximum nullable Float * value. */ public static <TSource> Float max(Enumerable<TSource> source, NullableFloatFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.FLOAT_MAX); } /** * Invokes a transform function on each element of a * generic sequence and returns the maximum resulting * value. */ public static <TSource, TResult extends Comparable<TResult>> TResult max(Enumerable<TSource> source, Function1<TSource, TResult> selector) { Function2<TResult, TResult, TResult> max = maxFunction(); return aggregate(source.select(selector), null, max); } /** * Returns the minimum value in a generic * sequence. */ public static <TSource extends Comparable<TSource>> TSource min(Enumerable<TSource> source) { Function2<TSource, TSource, TSource> min = minFunction(); return aggregate(source, null, min); } @SuppressWarnings("unchecked") private static <TSource extends Comparable<TSource>> Function2<TSource, TSource, TSource> minFunction() { return (Function2<TSource, TSource, TSource>) Extensions.COMPARABLE_MIN; } @SuppressWarnings("unchecked") private static <TSource extends Comparable<TSource>> Function2<TSource, TSource, TSource> maxFunction() { return (Function2<TSource, TSource, TSource>) Extensions.COMPARABLE_MAX; } /** * Invokes a transform function on each element of a * sequence and returns the minimum Decimal value. */ public static <TSource> BigDecimal min(Enumerable<TSource> source, BigDecimalFunction1<TSource> selector) { Function2<BigDecimal, BigDecimal, BigDecimal> min = minFunction(); return aggregate(source.select(selector), null, min); } /** * Invokes a transform function on each element of a * sequence and returns the minimum nullable Decimal * value. */ public static <TSource> BigDecimal min(Enumerable<TSource> source, NullableBigDecimalFunction1<TSource> selector) { Function2<BigDecimal, BigDecimal, BigDecimal> min = minFunction(); return aggregate(source.select(selector), null, min); } /** * Invokes a transform function on each element of a * sequence and returns the minimum Double value. */ public static <TSource> double min(Enumerable<TSource> source, DoubleFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.DOUBLE_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum nullable Double * value. */ public static <TSource> Double min(Enumerable<TSource> source, NullableDoubleFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.DOUBLE_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum int value. */ public static <TSource> int min(Enumerable<TSource> source, IntegerFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.INTEGER_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum nullable int value. (Defined * by Enumerable.) */ public static <TSource> Integer min(Enumerable<TSource> source, NullableIntegerFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.INTEGER_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum long value. */ public static <TSource> long min(Enumerable<TSource> source, LongFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.LONG_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum nullable long value. (Defined * by Enumerable.) */ public static <TSource> Long min(Enumerable<TSource> source, NullableLongFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.LONG_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum Float value. */ public static <TSource> float min(Enumerable<TSource> source, FloatFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), null, Extensions.FLOAT_MIN); } /** * Invokes a transform function on each element of a * sequence and returns the minimum nullable Float * value. */ public static <TSource> Float min(Enumerable<TSource> source, NullableFloatFunction1<TSource> selector) { return aggregate(source.select(selector), null, Extensions.FLOAT_MIN); } /** * Invokes a transform function on each element of a * generic sequence and returns the minimum resulting * value. */ public static <TSource, TResult extends Comparable<TResult>> TResult min(Enumerable<TSource> source, Function1<TSource, TResult> selector) { Function2<TResult, TResult, TResult> min = minFunction(); return aggregate(source.select(selector), null, min); } /** * Filters the elements of an Enumerable based on a * specified type. * * <p>Analogous to LINQ's Enumerable.OfType extension method.</p> * * @param clazz Target type * @param <TResult> Target type * * @return Collection of T2 */ public static <TSource, TResult> Enumerable<TResult> ofType(Enumerable<TSource> enumerable, Class<TResult> clazz) { //noinspection unchecked return (Enumerable) where(enumerable, Functions.<TSource, TResult>ofTypePredicate(clazz)); } /** * Sorts the elements of a sequence in ascending * order according to a key. */ public static <TSource, TKey extends Comparable> Enumerable<TSource> orderBy(Enumerable<TSource> source, Function1<TSource, TKey> keySelector) { return orderBy(source, keySelector, null); } /** * Sorts the elements of a sequence in ascending * order by using a specified comparer. */ public static <TSource, TKey> Enumerable<TSource> orderBy(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator) { // NOTE: TreeMap allows null comparator. But the caller of this method // must supply a comparator if the key does not extend Comparable. // Otherwise there will be a ClassCastException while retrieving. final Map<TKey, List<TSource>> map = new TreeMap<>(comparator); LookupImpl<TKey, TSource> lookup = toLookup_(map, source, keySelector, Functions.<TSource>identitySelector()); return lookup.valuesEnumerable(); } /** * Sorts the elements of a sequence in descending * order according to a key. */ public static <TSource, TKey extends Comparable> Enumerable<TSource> orderByDescending( Enumerable<TSource> source, Function1<TSource, TKey> keySelector) { return orderBy(source, keySelector, Collections.<TKey>reverseOrder()); } /** * Sorts the elements of a sequence in descending * order by using a specified comparer. */ public static <TSource, TKey> Enumerable<TSource> orderByDescending(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator) { return orderBy(source, keySelector, Collections.reverseOrder(comparator)); } /** * Inverts the order of the elements in a * sequence. */ public static <TSource> Enumerable<TSource> reverse(Enumerable<TSource> source) { final List<TSource> list = toList(source); final int n = list.size(); return Linq4j.asEnumerable(new AbstractList<TSource>() { public TSource get(int index) { return list.get(n - 1 - index); } public int size() { return n; } }); } /** * Projects each element of a sequence into a new form. */ public static <TSource, TResult> Enumerable<TResult> select(final Enumerable<TSource> source, final Function1<TSource, TResult> selector) { if (selector == Functions.identitySelector()) { //noinspection unchecked return (Enumerable<TResult>) source; } return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { final Enumerator<TSource> enumerator = source.enumerator(); public TResult current() { return selector.apply(enumerator.current()); } public boolean moveNext() { return enumerator.moveNext(); } public void reset() { enumerator.reset(); } public void close() { enumerator.close(); } }; } }; } /** * Projects each element of a sequence into a new * form by incorporating the element's index. */ public static <TSource, TResult> Enumerable<TResult> select(final Enumerable<TSource> source, final Function2<TSource, Integer, TResult> selector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { final Enumerator<TSource> enumerator = source.enumerator(); int n = -1; public TResult current() { return selector.apply(enumerator.current(), n); } public boolean moveNext() { if (enumerator.moveNext()) { ++n; return true; } else { return false; } } public void reset() { enumerator.reset(); } public void close() { enumerator.close(); } }; } }; } /** * Projects each element of a sequence to an * {@code Enumerable<TSource>} and flattens the resulting sequences into one * sequence. */ public static <TSource, TResult> Enumerable<TResult> selectMany(final Enumerable<TSource> source, final Function1<TSource, Enumerable<TResult>> selector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { Enumerator<TSource> sourceEnumerator = source.enumerator(); Enumerator<TResult> resultEnumerator = Linq4j.emptyEnumerator(); public TResult current() { return resultEnumerator.current(); } public boolean moveNext() { for (;;) { if (resultEnumerator.moveNext()) { return true; } if (!sourceEnumerator.moveNext()) { return false; } resultEnumerator = selector.apply(sourceEnumerator.current()).enumerator(); } } public void reset() { sourceEnumerator.reset(); resultEnumerator = Linq4j.emptyEnumerator(); } public void close() { sourceEnumerator.close(); resultEnumerator.close(); } }; } }; } /** * Projects each element of a sequence to an * {@code Enumerable<TSource>}, and flattens the resulting sequences into one * sequence. The index of each source element is used in the * projected form of that element. */ public static <TSource, TResult> Enumerable<TResult> selectMany(final Enumerable<TSource> source, final Function2<TSource, Integer, Enumerable<TResult>> selector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { int index = -1; Enumerator<TSource> sourceEnumerator = source.enumerator(); Enumerator<TResult> resultEnumerator = Linq4j.emptyEnumerator(); public TResult current() { return resultEnumerator.current(); } public boolean moveNext() { for (;;) { if (resultEnumerator.moveNext()) { return true; } if (!sourceEnumerator.moveNext()) { return false; } index += 1; resultEnumerator = selector.apply(sourceEnumerator.current(), index).enumerator(); } } public void reset() { sourceEnumerator.reset(); resultEnumerator = Linq4j.emptyEnumerator(); } public void close() { sourceEnumerator.close(); resultEnumerator.close(); } }; } }; } /** * Projects each element of a sequence to an * {@code Enumerable<TSource>}, flattens the resulting sequences into one * sequence, and invokes a result selector function on each * element therein. The index of each source element is used in * the intermediate projected form of that element. */ public static <TSource, TCollection, TResult> Enumerable<TResult> selectMany(final Enumerable<TSource> source, final Function2<TSource, Integer, Enumerable<TCollection>> collectionSelector, final Function2<TSource, TCollection, TResult> resultSelector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { int index = -1; Enumerator<TSource> sourceEnumerator = source.enumerator(); Enumerator<TCollection> collectionEnumerator = Linq4j.emptyEnumerator(); Enumerator<TResult> resultEnumerator = Linq4j.emptyEnumerator(); public TResult current() { return resultEnumerator.current(); } public boolean moveNext() { for (;;) { if (resultEnumerator.moveNext()) { return true; } if (!sourceEnumerator.moveNext()) { return false; } index += 1; final TSource sourceElement = sourceEnumerator.current(); collectionEnumerator = collectionSelector.apply(sourceElement, index).enumerator(); resultEnumerator = new TransformedEnumerator<TCollection, TResult>( collectionEnumerator) { protected TResult transform(TCollection collectionElement) { return resultSelector.apply(sourceElement, collectionElement); } }; } } public void reset() { sourceEnumerator.reset(); resultEnumerator = Linq4j.emptyEnumerator(); } public void close() { sourceEnumerator.close(); resultEnumerator.close(); } }; } }; } /** * Projects each element of a sequence to an * {@code Enumerable<TSource>}, flattens the resulting sequences into one * sequence, and invokes a result selector function on each * element therein. */ public static <TSource, TCollection, TResult> Enumerable<TResult> selectMany(final Enumerable<TSource> source, final Function1<TSource, Enumerable<TCollection>> collectionSelector, final Function2<TSource, TCollection, TResult> resultSelector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { Enumerator<TSource> sourceEnumerator = source.enumerator(); Enumerator<TCollection> collectionEnumerator = Linq4j.emptyEnumerator(); Enumerator<TResult> resultEnumerator = Linq4j.emptyEnumerator(); public TResult current() { return resultEnumerator.current(); } public boolean moveNext() { boolean incremented = false; for (;;) { if (resultEnumerator.moveNext()) { return true; } if (!sourceEnumerator.moveNext()) { return false; } final TSource sourceElement = sourceEnumerator.current(); collectionEnumerator = collectionSelector.apply(sourceElement).enumerator(); resultEnumerator = new TransformedEnumerator<TCollection, TResult>( collectionEnumerator) { protected TResult transform(TCollection collectionElement) { return resultSelector.apply(sourceElement, collectionElement); } }; } } public void reset() { sourceEnumerator.reset(); resultEnumerator = Linq4j.emptyEnumerator(); } public void close() { sourceEnumerator.close(); resultEnumerator.close(); } }; } }; } /** * Determines whether two sequences are equal by * comparing the elements by using the default equality comparer * for their type. */ public static <TSource> boolean sequenceEqual(Enumerable<TSource> first, Enumerable<TSource> second) { return sequenceEqual(first, second, null); } /** * Determines whether two sequences are equal by * comparing their elements by using a specified * {@code EqualityComparer<TSource>}. */ public static <TSource> boolean sequenceEqual(Enumerable<TSource> first, Enumerable<TSource> second, EqualityComparer<TSource> comparer) { Objects.requireNonNull(first); Objects.requireNonNull(second); if (comparer == null) { comparer = new EqualityComparer<TSource>() { public boolean equal(TSource v1, TSource v2) { return Objects.equals(v1, v2); } public int hashCode(TSource tSource) { return Objects.hashCode(tSource); } }; } final CollectionEnumerable<TSource> firstCollection = first instanceof CollectionEnumerable ? ((CollectionEnumerable<TSource>) first) : null; if (firstCollection != null) { final CollectionEnumerable<TSource> secondCollection = second instanceof CollectionEnumerable ? ((CollectionEnumerable<TSource>) second) : null; if (secondCollection != null) { if (firstCollection.getCollection().size() != secondCollection.getCollection().size()) { return false; } } } try (Enumerator<TSource> os1 = first.enumerator(); Enumerator<TSource> os2 = second.enumerator()) { while (os1.moveNext()) { if (!(os2.moveNext() && comparer.equal(os1.current(), os2.current()))) { return false; } } return !os2.moveNext(); } } /** * Returns the only element of a sequence, and throws * an exception if there is not exactly one element in the * sequence. */ public static <TSource> TSource single(Enumerable<TSource> source) { TSource toRet = null; try (Enumerator<TSource> os = source.enumerator()) { if (os.moveNext()) { toRet = os.current(); if (os.moveNext()) { throw new IllegalStateException(); } } if (toRet != null) { return toRet; } throw new IllegalStateException(); } } /** * Returns the only element of a sequence that * satisfies a specified condition, and throws an exception if * more than one such element exists. */ public static <TSource> TSource single(Enumerable<TSource> source, Predicate1<TSource> predicate) { TSource toRet = null; try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { if (predicate.apply(os.current())) { if (toRet == null) { toRet = os.current(); } else { throw new IllegalStateException(); } } } if (toRet != null) { return toRet; } throw new IllegalStateException(); } } /** * Returns the only element of a sequence, or a * default value if the sequence is empty; this method throws an * exception if there is more than one element in the * sequence. */ public static <TSource> TSource singleOrDefault(Enumerable<TSource> source) { TSource toRet = null; try (Enumerator<TSource> os = source.enumerator()) { if (os.moveNext()) { toRet = os.current(); } if (os.moveNext()) { return null; } return toRet; } } /** * Returns the only element of a sequence that * satisfies a specified condition or a default value if no such * element exists; this method throws an exception if more than * one element satisfies the condition. */ public static <TSource> TSource singleOrDefault(Enumerable<TSource> source, Predicate1<TSource> predicate) { TSource toRet = null; for (TSource s : source) { if (predicate.apply(s)) { if (toRet != null) { return null; } else { toRet = s; } } } return toRet; } /** * Bypasses a specified number of elements in a * sequence and then returns the remaining elements. */ public static <TSource> Enumerable<TSource> skip(Enumerable<TSource> source, final int count) { return skipWhile(source, new Predicate2<TSource, Integer>() { public boolean apply(TSource v1, Integer v2) { // Count is 1-based return v2 < count; } }); } /** * Bypasses elements in a sequence as long as a * specified condition is true and then returns the remaining * elements. */ public static <TSource> Enumerable<TSource> skipWhile(Enumerable<TSource> source, Predicate1<TSource> predicate) { return skipWhile(source, Functions.<TSource, Integer>toPredicate2(predicate)); } /** * Bypasses elements in a sequence as long as a * specified condition is true and then returns the remaining * elements. The element's index is used in the logic of the * predicate function. */ public static <TSource> Enumerable<TSource> skipWhile(final Enumerable<TSource> source, final Predicate2<TSource, Integer> predicate) { return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { return new SkipWhileEnumerator<>(source.enumerator(), predicate); } }; } /** * Computes the sum of the sequence of Decimal values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> BigDecimal sum(Enumerable<TSource> source, BigDecimalFunction1<TSource> selector) { return aggregate(source.select(selector), BigDecimal.ZERO, Extensions.BIG_DECIMAL_SUM); } /** * Computes the sum of the sequence of nullable * Decimal values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> BigDecimal sum(Enumerable<TSource> source, NullableBigDecimalFunction1<TSource> selector) { return aggregate(source.select(selector), BigDecimal.ZERO, Extensions.BIG_DECIMAL_SUM); } /** * Computes the sum of the sequence of Double values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> double sum(Enumerable<TSource> source, DoubleFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), 0d, Extensions.DOUBLE_SUM); } /** * Computes the sum of the sequence of nullable * Double values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> Double sum(Enumerable<TSource> source, NullableDoubleFunction1<TSource> selector) { return aggregate(source.select(selector), 0d, Extensions.DOUBLE_SUM); } /** * Computes the sum of the sequence of int values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> int sum(Enumerable<TSource> source, IntegerFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), 0, Extensions.INTEGER_SUM); } /** * Computes the sum of the sequence of nullable int * values that are obtained by invoking a transform function on * each element of the input sequence. */ public static <TSource> Integer sum(Enumerable<TSource> source, NullableIntegerFunction1<TSource> selector) { return aggregate(source.select(selector), 0, Extensions.INTEGER_SUM); } /** * Computes the sum of the sequence of long values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> long sum(Enumerable<TSource> source, LongFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), 0L, Extensions.LONG_SUM); } /** * Computes the sum of the sequence of nullable long * values that are obtained by invoking a transform function on * each element of the input sequence. */ public static <TSource> Long sum(Enumerable<TSource> source, NullableLongFunction1<TSource> selector) { return aggregate(source.select(selector), 0L, Extensions.LONG_SUM); } /** * Computes the sum of the sequence of Float values * that are obtained by invoking a transform function on each * element of the input sequence. */ public static <TSource> float sum(Enumerable<TSource> source, FloatFunction1<TSource> selector) { return aggregate(source.select(adapt(selector)), 0F, Extensions.FLOAT_SUM); } /** * Computes the sum of the sequence of nullable * Float values that are obtained by invoking a transform * function on each element of the input sequence. */ public static <TSource> Float sum(Enumerable<TSource> source, NullableFloatFunction1<TSource> selector) { return aggregate(source.select(selector), 0F, Extensions.FLOAT_SUM); } /** * Returns a specified number of contiguous elements * from the start of a sequence. */ public static <TSource> Enumerable<TSource> take(Enumerable<TSource> source, final int count) { return takeWhile(source, new Predicate2<TSource, Integer>() { public boolean apply(TSource v1, Integer v2) { // Count is 1-based return v2 < count; } }); } /** * Returns a specified number of contiguous elements * from the start of a sequence. */ public static <TSource> Enumerable<TSource> take(Enumerable<TSource> source, final long count) { return takeWhileLong(source, new Predicate2<TSource, Long>() { public boolean apply(TSource v1, Long v2) { // Count is 1-based return v2 < count; } }); } /** * Returns elements from a sequence as long as a * specified condition is true. */ public static <TSource> Enumerable<TSource> takeWhile(Enumerable<TSource> source, final Predicate1<TSource> predicate) { return takeWhile(source, Functions.<TSource, Integer>toPredicate2(predicate)); } /** * Returns elements from a sequence as long as a * specified condition is true. The element's index is used in the * logic of the predicate function. */ public static <TSource> Enumerable<TSource> takeWhile(final Enumerable<TSource> source, final Predicate2<TSource, Integer> predicate) { return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { return new TakeWhileEnumerator<>(source.enumerator(), predicate); } }; } /** * Returns elements from a sequence as long as a * specified condition is true. The element's index is used in the * logic of the predicate function. */ public static <TSource> Enumerable<TSource> takeWhileLong(final Enumerable<TSource> source, final Predicate2<TSource, Long> predicate) { return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { return new TakeWhileLongEnumerator<>(source.enumerator(), predicate); } }; } /** * Performs a subsequent ordering of the elements in a sequence according * to a key. */ public static <TSource, TKey> OrderedEnumerable<TSource> createOrderedEnumerable( OrderedEnumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator, boolean descending) { throw Extensions.todo(); } /** * Performs a subsequent ordering of the elements in a sequence in * ascending order according to a key. */ public static <TSource, TKey extends Comparable<TKey>> OrderedEnumerable<TSource> thenBy( OrderedEnumerable<TSource> source, Function1<TSource, TKey> keySelector) { return createOrderedEnumerable(source, keySelector, Extensions.<TKey>comparableComparator(), false); } /** * Performs a subsequent ordering of the elements in a sequence in * ascending order according to a key, using a specified comparator. */ public static <TSource, TKey> OrderedEnumerable<TSource> thenBy(OrderedEnumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator) { return createOrderedEnumerable(source, keySelector, comparator, false); } /** * Performs a subsequent ordering of the elements in a sequence in * descending order according to a key. */ public static <TSource, TKey extends Comparable<TKey>> OrderedEnumerable<TSource> thenByDescending( OrderedEnumerable<TSource> source, Function1<TSource, TKey> keySelector) { return createOrderedEnumerable(source, keySelector, Extensions.<TKey>comparableComparator(), true); } /** * Performs a subsequent ordering of the elements in a sequence in * descending order according to a key, using a specified comparator. */ public static <TSource, TKey> OrderedEnumerable<TSource> thenByDescending(OrderedEnumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator) { return createOrderedEnumerable(source, keySelector, comparator, true); } /** * Creates a Map<TKey, TValue> from an * Enumerable<TSource> according to a specified key selector * function. * * <p>NOTE: Called {@code toDictionary} in LINQ.NET.</p> */ public static <TSource, TKey> Map<TKey, TSource> toMap(Enumerable<TSource> source, Function1<TSource, TKey> keySelector) { return toMap(source, keySelector, Functions.<TSource>identitySelector()); } /** * Creates a {@code Map<TKey, TValue>} from an * {@code Enumerable<TSource>} according to a specified key selector function * and key comparer. */ public static <TSource, TKey> Map<TKey, TSource> toMap(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, EqualityComparer<TKey> comparer) { return toMap(source, keySelector, Functions.<TSource>identitySelector(), comparer); } /** * Creates a {@code Map<TKey, TValue>} from an * {@code Enumerable<TSource>} according to specified key selector and element * selector functions. */ public static <TSource, TKey, TElement> Map<TKey, TElement> toMap(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector) { // Use LinkedHashMap because groupJoin requires order of keys to be // preserved. final Map<TKey, TElement> map = new LinkedHashMap<>(); try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); map.put(keySelector.apply(o), elementSelector.apply(o)); } } return map; } /** * Creates a {@code Map<TKey, TValue>} from an * {@code Enumerable<TSource>} according to a specified key selector function, * a comparer, and an element selector function. */ public static <TSource, TKey, TElement> Map<TKey, TElement> toMap(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector, EqualityComparer<TKey> comparer) { // Use LinkedHashMap because groupJoin requires order of keys to be // preserved. final Map<TKey, TElement> map = new WrapMap<>(new Function0<Map<Wrapped<TKey>, TElement>>() { public Map<Wrapped<TKey>, TElement> apply() { return new LinkedHashMap<>(); } }, comparer); try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); map.put(keySelector.apply(o), elementSelector.apply(o)); } } return map; } /** * Creates a {@code List<TSource>} from an {@code Enumerable<TSource>}. */ @SuppressWarnings("unchecked") public static <TSource> List<TSource> toList(Enumerable<TSource> source) { if (source instanceof List && source instanceof RandomAccess) { return (List<TSource>) source; } else { return source.into(source instanceof Collection ? new ArrayList<TSource>(((Collection) source).size()) : new ArrayList<TSource>()); } } /** * Creates a Lookup<TKey, TElement> from an * Enumerable<TSource> according to a specified key selector * function. */ public static <TSource, TKey> Lookup<TKey, TSource> toLookup(Enumerable<TSource> source, Function1<TSource, TKey> keySelector) { return toLookup(source, keySelector, Functions.<TSource>identitySelector()); } /** * Creates a {@code Lookup<TKey, TElement>} from an * {@code Enumerable<TSource>} according to a specified key selector function * and key comparer. */ public static <TSource, TKey> Lookup<TKey, TSource> toLookup(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, EqualityComparer<TKey> comparer) { return toLookup(source, keySelector, Functions.<TSource>identitySelector(), comparer); } /** * Creates a {@code Lookup<TKey, TElement>} from an * {@code Enumerable<TSource>} according to specified key selector and element * selector functions. */ public static <TSource, TKey, TElement> Lookup<TKey, TElement> toLookup(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector) { final Map<TKey, List<TElement>> map = new HashMap<>(); return toLookup_(map, source, keySelector, elementSelector); } static <TSource, TKey, TElement> LookupImpl<TKey, TElement> toLookup_(Map<TKey, List<TElement>> map, Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector) { try (Enumerator<TSource> os = source.enumerator()) { while (os.moveNext()) { TSource o = os.current(); final TKey key = keySelector.apply(o); List<TElement> list = map.get(key); if (list == null) { // for first entry, use a singleton list to save space list = Collections.singletonList(elementSelector.apply(o)); } else { if (list.size() == 1) { // when we go from 1 to 2 elements, switch to array list TElement element = list.get(0); list = new ArrayList<>(); list.add(element); } list.add(elementSelector.apply(o)); } map.put(key, list); } } return new LookupImpl<>(map); } /** * Creates a {@code Lookup<TKey, TElement>} from an * {@code Enumerable<TSource>} according to a specified key selector function, * a comparer and an element selector function. */ public static <TSource, TKey, TElement> Lookup<TKey, TElement> toLookup(Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Function1<TSource, TElement> elementSelector, EqualityComparer<TKey> comparer) { return toLookup_(new WrapMap<>(new Function0<Map<Wrapped<TKey>, List<TElement>>>() { public Map<Wrapped<TKey>, List<TElement>> apply() { return new HashMap<>(); } }, comparer), source, keySelector, elementSelector); } /** * Produces the set union of two sequences by using * the default equality comparer. */ public static <TSource> Enumerable<TSource> union(Enumerable<TSource> source0, Enumerable<TSource> source1) { Set<TSource> set = new HashSet<>(); source0.into(set); source1.into(set); return Linq4j.asEnumerable(set); } /** * Produces the set union of two sequences by using a * specified EqualityComparer<TSource>. */ public static <TSource> Enumerable<TSource> union(Enumerable<TSource> source0, Enumerable<TSource> source1, final EqualityComparer<TSource> comparer) { if (comparer == Functions.identityComparer()) { return union(source0, source1); } Set<Wrapped<TSource>> set = new HashSet<>(); Function1<TSource, Wrapped<TSource>> wrapper = wrapperFor(comparer); Function1<Wrapped<TSource>, TSource> unwrapper = unwrapper(); source0.select(wrapper).into(set); source1.select(wrapper).into(set); return Linq4j.asEnumerable(set).select(unwrapper); } private static <TSource> Function1<Wrapped<TSource>, TSource> unwrapper() { return new Function1<Wrapped<TSource>, TSource>() { public TSource apply(Wrapped<TSource> a0) { return a0.element; } }; } private static <TSource> Function1<TSource, Wrapped<TSource>> wrapperFor( final EqualityComparer<TSource> comparer) { return new Function1<TSource, Wrapped<TSource>>() { public Wrapped<TSource> apply(TSource a0) { return Wrapped.upAs(comparer, a0); } }; } /** * Filters a sequence of values based on a * predicate. */ public static <TSource> Enumerable<TSource> where(final Enumerable<TSource> source, final Predicate1<TSource> predicate) { assert predicate != null; return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { final Enumerator<TSource> enumerator = source.enumerator(); return EnumerableDefaults.where(enumerator, predicate); } }; } private static <TSource> Enumerator<TSource> where(final Enumerator<TSource> enumerator, final Predicate1<TSource> predicate) { return new Enumerator<TSource>() { public TSource current() { return enumerator.current(); } public boolean moveNext() { while (enumerator.moveNext()) { if (predicate.apply(enumerator.current())) { return true; } } return false; } public void reset() { enumerator.reset(); } public void close() { enumerator.close(); } }; } /** * Filters a sequence of values based on a * predicate. Each element's index is used in the logic of the * predicate function. */ public static <TSource> Enumerable<TSource> where(final Enumerable<TSource> source, final Predicate2<TSource, Integer> predicate) { return new AbstractEnumerable<TSource>() { public Enumerator<TSource> enumerator() { return new Enumerator<TSource>() { final Enumerator<TSource> enumerator = source.enumerator(); int n = -1; public TSource current() { return enumerator.current(); } public boolean moveNext() { while (enumerator.moveNext()) { ++n; if (predicate.apply(enumerator.current(), n)) { return true; } } return false; } public void reset() { enumerator.reset(); n = -1; } public void close() { enumerator.close(); } }; } }; } /** * Applies a specified function to the corresponding * elements of two sequences, producing a sequence of the * results. */ public static <T0, T1, TResult> Enumerable<TResult> zip(final Enumerable<T0> first, final Enumerable<T1> second, final Function2<T0, T1, TResult> resultSelector) { return new AbstractEnumerable<TResult>() { public Enumerator<TResult> enumerator() { return new Enumerator<TResult>() { final Enumerator<T0> e1 = first.enumerator(); final Enumerator<T1> e2 = second.enumerator(); public TResult current() { return resultSelector.apply(e1.current(), e2.current()); } public boolean moveNext() { return e1.moveNext() && e2.moveNext(); } public void reset() { e1.reset(); e2.reset(); } public void close() { e1.close(); e2.close(); } }; } }; } public static <T> OrderedQueryable<T> asOrderedQueryable(Enumerable<T> source) { //noinspection unchecked return source instanceof OrderedQueryable ? ((OrderedQueryable<T>) source) : new EnumerableOrderedQueryable<>(source, (Class) Object.class, null, null); } /** Default implementation of {@link ExtendedEnumerable#into(Collection)}. */ public static <T, C extends Collection<? super T>> C into(Enumerable<T> source, C sink) { try (Enumerator<T> enumerator = source.enumerator()) { while (enumerator.moveNext()) { T t = enumerator.current(); sink.add(t); } } return sink; } /** Default implementation of {@link ExtendedEnumerable#removeAll(Collection)}. */ public static <T, C extends Collection<? super T>> C remove(Enumerable<T> source, C sink) { List<T> tempList = new ArrayList<>(); source.into(tempList); sink.removeAll(tempList); return sink; } /** Enumerable that implements take-while. */ static class TakeWhileEnumerator<TSource> implements Enumerator<TSource> { private final Enumerator<TSource> enumerator; private final Predicate2<TSource, Integer> predicate; boolean done = false; int n = -1; public TakeWhileEnumerator(Enumerator<TSource> enumerator, Predicate2<TSource, Integer> predicate) { this.enumerator = enumerator; this.predicate = predicate; } public TSource current() { return enumerator.current(); } public boolean moveNext() { if (!done) { if (enumerator.moveNext() && predicate.apply(enumerator.current(), ++n)) { return true; } else { done = true; } } return false; } public void reset() { enumerator.reset(); done = false; n = -1; } public void close() { enumerator.close(); } } /** Enumerable that implements take-while. */ static class TakeWhileLongEnumerator<TSource> implements Enumerator<TSource> { private final Enumerator<TSource> enumerator; private final Predicate2<TSource, Long> predicate; boolean done = false; long n = -1; public TakeWhileLongEnumerator(Enumerator<TSource> enumerator, Predicate2<TSource, Long> predicate) { this.enumerator = enumerator; this.predicate = predicate; } public TSource current() { return enumerator.current(); } public boolean moveNext() { if (!done) { if (enumerator.moveNext() && predicate.apply(enumerator.current(), ++n)) { return true; } else { done = true; } } return false; } public void reset() { enumerator.reset(); done = false; n = -1; } public void close() { enumerator.close(); } } /** Enumerator that implements skip-while. */ static class SkipWhileEnumerator<TSource> implements Enumerator<TSource> { private final Enumerator<TSource> enumerator; private final Predicate2<TSource, Integer> predicate; boolean started = false; int n = -1; public SkipWhileEnumerator(Enumerator<TSource> enumerator, Predicate2<TSource, Integer> predicate) { this.enumerator = enumerator; this.predicate = predicate; } public TSource current() { return enumerator.current(); } public boolean moveNext() { for (;;) { if (!enumerator.moveNext()) { return false; } if (started) { return true; } if (!predicate.apply(enumerator.current(), ++n)) { started = true; return true; } } } public void reset() { enumerator.reset(); started = false; n = -1; } public void close() { enumerator.close(); } } /** Enumerator that casts each value. */ static class CastingEnumerator<T> implements Enumerator<T> { private final Enumerator<?> enumerator; private final Class<T> clazz; public CastingEnumerator(Enumerator<?> enumerator, Class<T> clazz) { this.enumerator = enumerator; this.clazz = clazz; } public T current() { return clazz.cast(enumerator.current()); } public boolean moveNext() { return enumerator.moveNext(); } public void reset() { enumerator.reset(); } public void close() { enumerator.close(); } } /** Value wrapped with a comparer. */ private static class Wrapped<T> { private final EqualityComparer<T> comparer; private final T element; private Wrapped(EqualityComparer<T> comparer, T element) { this.comparer = comparer; this.element = element; } static <T> Wrapped<T> upAs(EqualityComparer<T> comparer, T element) { return new Wrapped<>(comparer, element); } @Override public int hashCode() { return comparer.hashCode(element); } @Override public boolean equals(Object obj) { //noinspection unchecked return obj == this || obj instanceof Wrapped && comparer.equal(element, ((Wrapped<T>) obj).element); } public T unwrap() { return element; } } /** Map that wraps each value. */ private static class WrapMap<K, V> extends AbstractMap<K, V> { private final Map<Wrapped<K>, V> map; private final EqualityComparer<K> comparer; protected WrapMap(Function0<Map<Wrapped<K>, V>> mapProvider, EqualityComparer<K> comparer) { this.map = mapProvider.apply(); this.comparer = comparer; } @Override public Set<Entry<K, V>> entrySet() { return new AbstractSet<Entry<K, V>>() { @Override public Iterator<Entry<K, V>> iterator() { final Iterator<Entry<Wrapped<K>, V>> iterator = map.entrySet().iterator(); return new Iterator<Entry<K, V>>() { public boolean hasNext() { return iterator.hasNext(); } public Entry<K, V> next() { Entry<Wrapped<K>, V> next = iterator.next(); return new SimpleEntry<>(next.getKey().element, next.getValue()); } public void remove() { iterator.remove(); } }; } @Override public int size() { return map.size(); } }; } @Override public boolean containsKey(Object key) { return map.containsKey(wrap((K) key)); } private Wrapped<K> wrap(K key) { return Wrapped.upAs(comparer, key); } @Override public V get(Object key) { return map.get(wrap((K) key)); } @Override public V put(K key, V value) { return map.put(wrap(key), value); } @Override public V remove(Object key) { return map.remove(wrap((K) key)); } @Override public void clear() { map.clear(); } @Override public Collection<V> values() { return map.values(); } } /** Reads a populated map, applying a selector function. */ private static class LookupResultEnumerable<TResult, TKey, TAccumulate> extends AbstractEnumerable2<TResult> { private final Map<TKey, TAccumulate> map; private final Function2<TKey, TAccumulate, TResult> resultSelector; public LookupResultEnumerable(Map<TKey, TAccumulate> map, Function2<TKey, TAccumulate, TResult> resultSelector) { this.map = map; this.resultSelector = resultSelector; } public Iterator<TResult> iterator() { final Iterator<Map.Entry<TKey, TAccumulate>> iterator = map.entrySet().iterator(); return new Iterator<TResult>() { public boolean hasNext() { return iterator.hasNext(); } public TResult next() { final Map.Entry<TKey, TAccumulate> entry = iterator.next(); return resultSelector.apply(entry.getKey(), entry.getValue()); } public void remove() { throw new UnsupportedOperationException(); } }; } } /** Enumerator that performs a merge join on its sorted inputs. */ private static class MergeJoinEnumerator<TResult, TSource, TInner, TKey extends Comparable<TKey>> implements Enumerator<TResult> { final List<TSource> lefts = new ArrayList<>(); final List<TInner> rights = new ArrayList<>(); private final Enumerator<TSource> leftEnumerator; private final Enumerator<TInner> rightEnumerator; private final Function1<TSource, TKey> outerKeySelector; private final Function1<TInner, TKey> innerKeySelector; private final Function2<TSource, TInner, TResult> resultSelector; boolean done; Enumerator<List<Object>> cartesians; MergeJoinEnumerator(Enumerator<TSource> leftEnumerator, Enumerator<TInner> rightEnumerator, Function1<TSource, TKey> outerKeySelector, Function1<TInner, TKey> innerKeySelector, Function2<TSource, TInner, TResult> resultSelector) { this.leftEnumerator = leftEnumerator; this.rightEnumerator = rightEnumerator; this.outerKeySelector = outerKeySelector; this.innerKeySelector = innerKeySelector; this.resultSelector = resultSelector; start(); } private void start() { if (!leftEnumerator.moveNext() || !rightEnumerator.moveNext() || !advance()) { done = true; cartesians = Linq4j.emptyEnumerator(); } } /** Moves to the next key that is present in both sides. Populates * lefts and rights with the rows. Restarts the cross-join * enumerator. */ private boolean advance() { TSource left = leftEnumerator.current(); TKey leftKey = outerKeySelector.apply(left); TInner right = rightEnumerator.current(); TKey rightKey = innerKeySelector.apply(right); for (;;) { int c = leftKey.compareTo(rightKey); if (c == 0) { break; } if (c < 0) { if (!leftEnumerator.moveNext()) { done = true; return false; } left = leftEnumerator.current(); leftKey = outerKeySelector.apply(left); } else { if (!rightEnumerator.moveNext()) { done = true; return false; } right = rightEnumerator.current(); rightKey = innerKeySelector.apply(right); } } lefts.clear(); lefts.add(left); for (;;) { if (!leftEnumerator.moveNext()) { done = true; break; } left = leftEnumerator.current(); TKey leftKey2 = outerKeySelector.apply(left); int c = leftKey.compareTo(leftKey2); if (c != 0) { assert c < 0 : "not sorted"; break; } lefts.add(left); } rights.clear(); rights.add(right); for (;;) { if (!rightEnumerator.moveNext()) { done = true; break; } right = rightEnumerator.current(); TKey rightKey2 = innerKeySelector.apply(right); int c = rightKey.compareTo(rightKey2); if (c != 0) { assert c < 0 : "not sorted"; break; } rights.add(right); } cartesians = Linq4j .product(ImmutableList.of(Linq4j.<Object>enumerator(lefts), Linq4j.<Object>enumerator(rights))); return true; } public TResult current() { final List<Object> list = cartesians.current(); @SuppressWarnings("unchecked") final TSource left = (TSource) list.get(0); @SuppressWarnings("unchecked") final TInner right = (TInner) list.get(1); return resultSelector.apply(left, right); } public boolean moveNext() { for (;;) { if (cartesians.moveNext()) { return true; } if (done) { return false; } if (!advance()) { return false; } } } public void reset() { done = false; leftEnumerator.reset(); rightEnumerator.reset(); start(); } public void close() { } } } // End EnumerableDefaults.java