All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ix.internal.operators.Interactive Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/*
 * Copyright 2011-2016 David Karnok
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ix.internal.operators;

import ix.CloseableIterable;
import ix.CloseableIterator;
import ix.Enumerable;
import ix.Enumerator;
import ix.GroupedIterable;
import ix.Pair;
import ix.internal.util.IxHelperFunctions;
import ix.internal.util.LinkedBuffer;

import java.io.Closeable;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import rx.Notification;
import rx.Scheduler;
import rx.Subscription;
import rx.exceptions.Exceptions;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Actions;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.schedulers.Schedulers;

/**
 * The interactive (i.e., Iterable based) counterparts
 * of the Reactive operators.
 * 

The implementations of the operators are partially derived * from the Reactive operators.

* @see rx.Observable */ public final class Interactive { /** * Creates an iterable which traverses the source iterable and maintains a running sum value based * on the sum function parameter. Once the source is depleted, it * applies the divide function and returns its result. * This operator is a general base for averaging (where {@code sum(u, t) => u + t}, {@code divide(u, index) => u / index}), * summing (where {@code sum(u, t) => u + t}, and {@code divide(u, index) => u)}), * minimum, maximum, etc. * If the traversal of the source fails due an exception, that exception is reflected on the * {@code next()} call of the returned iterator. * The returned iterator will throw an UnsupportedOperationException * for its remove() method. * @param the source element type * @param the intermediate aggregation type * @param the resulting aggregation type * @param source the source of Ts * @param sum the function which takes the current intermediate value, * the current source value and should produce a new intermediate value. * for the first element of T, the U parameter will receive null * @param divide the function which takes the last intermediate value and a total count of Ts seen and should return the final aggregation value. * @return the new iterable */ public static Iterable aggregate( final Iterable source, final Func2 sum, final Func2 divide) { return new AggregateIterable(source, sum, divide); } /** * Returns an iterable which contains true if all * elements of the source iterable satisfy the predicate. * The operator might return a false before fully iterating the source. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param source the source of Ts * @param predicate the predicate * @return the new iterable */ public static Iterable all( final Iterable source, final Func1 predicate) { return new AllIterable(source, predicate); } /** * Tests if there is any element of the source that satisfies the given predicate function. * @param the source element type * @param source the source of Ts * @param predicate the predicate tester function * @return the new iterable */ public static Iterable any( final Iterable source, final Func1 predicate) { return any(filter(source, predicate)); } /** * Determines if the given source has any elements at all. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type, irrelevant here * @param source the source of Ts * @return the new iterable with a single true or false */ public static Iterable any( final Iterable source) { return new AnyIterable(source); } /** * Returns a pair of the maximum argument and value from the given sequence. * @param the element type of the sequence * @param the value type for the comparison, must be self comparable * @param source the source sequence * @param valueSelector the value selector function * @return the pair of the first maximum element and value, null if the sequence was empty */ public static > Pair argAndMax( Iterable source, Func1 valueSelector) { return argAndMax(source, valueSelector, IxHelperFunctions.comparator()); } /** * Returns a pair of the maximum argument and value from the given sequence. * @param the element type * @param the value type * @param source the source sequence of Ts * @param valueSelector the selector to extract the value from T * @param valueComparator the comparator to compare two values * @return the first pair of max argument and value or null if the source sequence was empty */ public static Pair argAndMax( Iterable source, Func1 valueSelector, Comparator valueComparator) { T arg = null; V max = null; boolean hasElement = false; Iterator it = source.iterator(); try { while (it.hasNext()) { T item = it.next(); V itemValue = valueSelector.call(item); if (!hasElement || valueComparator.compare(max, itemValue) < 0) { arg = item; max = itemValue; } hasElement = true; } if (hasElement) { return Pair.of(arg, max); } } finally { unsubscribe(it); } return null; } /** * Returns a pair of the maximum argument and value from the given sequence. * @param the element type of the sequence * @param the value type for the comparison, must be self comparable * @param source the source sequence * @param valueSelector the value selector function * @return the pair of the first maximum element and value, null if the sequence was empty */ public static > Pair argAndMin( Iterable source, Func1 valueSelector) { return argAndMin(source, valueSelector, IxHelperFunctions.comparator()); } /** * Returns a pair of the minimum argument and value from the given sequence. * @param the element type * @param the value type * @param source the source sequence of Ts * @param valueSelector the selector to extract the value from T * @param valueComparator the comparator to compare two values * @return the first pair of min argument and value or null if the source sequence was empty */ public static Pair argAndMin( Iterable source, Func1 valueSelector, final Comparator valueComparator) { return argAndMax(source, valueSelector, new Comparator() { @Override public int compare(V o1, V o2) { return valueComparator.compare(o2, o1); } }); } /** * Returns an iterable which averages the source BigDecimal values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source of BigDecimal values * @return the new iterable */ public static Iterable averageBigDecimal( Iterable source) { return aggregate(source, new Func2() { @Override public BigDecimal call(BigDecimal param1, BigDecimal param2) { return param1 != null ? param1.add(param2) : param2; } }, new Func2() { @Override public BigDecimal call(BigDecimal param1, Integer param2) { return param1.divide(new BigDecimal(param2), BigDecimal.ROUND_HALF_UP); } } ); } /** * Returns an iterable which averages the source BigInteger values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source of BigInteger values * @return the new iterable */ public static Iterable averageBigInteger( Iterable source) { return aggregate(source, new Func2() { @Override public BigInteger call(BigInteger param1, BigInteger param2) { return param1 != null ? param1.add(param2) : param2; } }, new Func2() { @Override public BigDecimal call(BigInteger param1, Integer param2) { return new BigDecimal(param1).divide(new BigDecimal(param2), BigDecimal.ROUND_HALF_UP); } } ); } /** * Returns an iterable which averages the source Double values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source of Double values * @return the new iterable */ public static Iterable averageDouble( Iterable source) { return aggregate(source, new Func2() { @Override public Double call(Double param1, Double param2) { return param1 != null ? param1 + param2 : param2.doubleValue(); } }, new Func2() { @Override public Double call(Double param1, Integer param2) { return param1 / param2; } } ); } /** * Returns an iterable which averages the source Float values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source of Float values * @return the new iterable */ public static Iterable averageFloat( Iterable source) { return aggregate(source, new Func2() { @Override public Float call(Float param1, Float param2) { return param1 != null ? param1 + param2 : param2.floatValue(); } }, new Func2() { @Override public Float call(Float param1, Integer param2) { return param1 / param2; } } ); } /** * Returns an iterable which averages the source Integer values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source of Integer values * @return the new iterable */ public static Iterable averageInt( Iterable source) { return aggregate(source, new Func2() { @Override public Double call(Double param1, Integer param2) { return param1 != null ? param1 + param2 : param2.doubleValue(); } }, new Func2() { @Override public Double call(Double param1, Integer param2) { return param1 / param2; } } ); } /** * Returns an iterable which averages the source Integer values. * The returned iterator will throw an UnsupportedOperationException * for its remove() method. * @param source the source of Integer values * @return the new iterable */ public static Iterable averageLong( Iterable source) { return aggregate(source, new Func2() { @Override public Double call(Double param1, Long param2) { return param1 != null ? param1 + param2 : param2.doubleValue(); } }, new Func2() { @Override public Double call(Double param1, Integer param2) { return param1 / param2; } } ); } /** * Returns an iterable which buffers the source elements * into bufferSize lists. * FIXME what to do on empty source or last chunk? *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param source the source of Ts * @param bufferSize the buffer size. * @return the new iterable */ public static Iterable> buffer( final Iterable source, final int bufferSize) { if (bufferSize <= 0) { throw new IllegalArgumentException("bufferSize <= 0"); } return new BufferIterable(source, bufferSize); } /** * Concatenate the given iterable sources one * after another in a way, that calling the second iterator() * only happens when there is no more element in the first iterator. *

The returned iterator forwards all remove() calls * to the current source (e.g., you can remove the same elements from * multiple collections with a single traversal on the concat result). * @param the element type * @param sources the list of iterables to concatenate * @return a new iterable */ public static Iterable concat( final Iterable> sources) { return new ConcatIterable(sources); } /** * Concatenate the given iterable sources one * after another in a way, that calling the second iterator() * only happens when there is no more element in the first iterator. *

The returned iterator forwards all remove() calls * to the current source (first or next). * @param the element type * @param first the first iterable * @param second the second iterable * @return the new iterable */ public static Iterable concat( final Iterable first, final Iterable second) { List> list = new LinkedList>(); list.add(first); list.add(second); return concat(list); } /** * Returns an iterable which checks for the existence of the supplied * value by comparing the elements of the source iterable using reference * and equals(). The iterable then returns a single true or false. * @param the source element type * @param source the source * @param value the value to check * @return the new iterable */ public static Iterable contains( final Iterable source, final Object value) { return any(source, new Func1() { @Override public Boolean call(T param1) { return param1 == value || (param1 != null && param1.equals(value)); } }); } /** * Counts the elements of the iterable source by using a 32 bit int. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @return the new iterable */ public static Iterable count( final Iterable source) { return new CountIterable(source); } /** * Counts the elements of the iterable source by using a 64 bit long. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @return the new iterable */ public static Iterable countLong( final Iterable source) { return new LongCountIterable(source); } /** * Defers the source iterable creation to registration time and * calls the given func for the actual source. * @param the element type * @param func the function that returns an iterable. * @return the new iterable */ public static Iterable defer( final Func0> func) { return new DeferIterable(func); } /** * Convert the source materialized elements into normal iterator behavior. * The returned iterator will throw an UnsupportedOperationException for its remove() method. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element types * @param source the source of T options * @return the new iterable */ public static Iterable dematerialize( final Iterable> source) { return new DematerializeIterable(source); } /** * Returns an iterable which filters its elements based if they were ever seen before in * the current iteration. * Value equality is computed by reference equality and equals() * @param the source element type * @param source the source of Ts * @return the new iterable */ public static Iterable distinct( final Iterable source) { return distinct(source, IxHelperFunctions.identity(), IxHelperFunctions.identity()); } /** * Returns an iterable which filters its elements by an unique key * in a way that when multiple source items produce the same key, only * the first one ever seen gets relayed further on. * Key equality is computed by reference equality and equals() * @param the source element type * @param the key element type * @param the output element type * @param source the source of Ts * @param keySelector the key selector for only-once filtering * @param valueSelector the value select for the output of the first key cases * @return the new iterable */ public static Iterable distinct( final Iterable source, final Func1 keySelector, final Func1 valueSelector) { return map(filterIndexed(source, new Func0>() { @Override public Func2 call() { return new Func2() { final Set memory = new HashSet(); @Override public Boolean call(Integer index, T param1) { return memory.add(keySelector.call(param1)); } }; } }) , new Func1() { @Override public V call(T param1) { return valueSelector.call(param1); } }); } /** * Creates an iterable which ensures that subsequent values of T are not equal (reference and equals). * @param the element type * @param source the source iterable * @return the new iterable */ public static Iterable distinctNext( final Iterable source) { return filterIndexed(source, new Func0>() { @Override public Func2 call() { return new Func2() { /** Is this the first element? */ boolean first = true; /** The last seen element. */ T last; @Override public Boolean call(Integer index, T param1) { if (first) { first = false; last = param1; return true; } if (last == param1 || (last != null && last.equals(param1))) { last = param1; return false; } last = param1; return true; } }; } }); } /** * Creates an iterable which ensures that subsequent values of * T are not equal in respect to the extracted keys (reference and equals). * @param the element type * @param the key type * @param source the source iterable * @param keyExtractor the function to extract the keys which will be compared * @return the new iterable */ public static Iterable distinctNext( final Iterable source, final Func1 keyExtractor) { return filterIndexed(source, new Func0>() { @Override public Func2 call() { return new Func2() { /** Is this the first element? */ boolean first = true; /** The last seen element. */ U last; @Override public Boolean call(Integer index, T param1) { U key = keyExtractor.call(param1); if (first) { first = false; last = key; return true; } if (last == key || (last != null && last.equals(key))) { last = key; return false; } last = key; return true; } }; } }); } /** * Construct a new iterable which will invoke the specified action * before the source value gets relayed through it. * Can be used to inject side-effects before returning a value. *

The returned iterator forwards all remove() calls * to the source.

* @param the returned element type * @param source the source iterable * @param action the action to invoke before each next() is returned. * @return the new iterable */ public static Iterable doOnNext( final Iterable source, final Action1 action) { return new DoOnNextIterable(source, action); } /** * Returns an iterable which reiterates over and over again on source * as long as the gate is true. The gate function is checked only * when a pass over the source stream was completed. * Note that using this operator on an empty iterable may result * in a direct infinite loop in hasNext() or next() calls depending on the gate function. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param source the source of Ts * @param gate the gate function to stop the repeat * @return the new iterable */ public static Iterable doWhile( final Iterable source, final Func0 gate) { return new DoWhileIterable(source, gate); } /** * Determines whether two iterables contain equal elements in the same * order. More specifically, this method returns {@code true} if * {@code iterable1} and {@code iterable2} contain the same number of * elements and every element of {@code iterable1} is equal to the * corresponding element of {@code iterable2}. * @param iterable1 the first iterable * @param iterable2 the second iterable * @return true if both iterables are either empty or contain the same number and equal items */ public static boolean elementsEqual(Iterable iterable1, Iterable iterable2) { Iterator iterator1 = iterable1.iterator(); Iterator iterator2 = iterable2.iterator(); return elementsEqual(iterator1, iterator2); } /** * Compares two iterators wether they contain the same element in terms of numbers * and nullsafe Object.equals(). * @param iterator1 the first iterator * @param iterator2 the second interator * @return true if they are equal */ public static boolean elementsEqual( Iterator iterator1, Iterator iterator2) { try { while (iterator1.hasNext()) { if (!iterator2.hasNext()) { return false; } Object o1 = iterator1.next(); Object o2 = iterator2.next(); if (!equal(o1, o2)) { return false; } } return !iterator2.hasNext(); } finally { unsubscribe(iterator1); unsubscribe(iterator2); } } /** * Returns an empty iterable which will not produce elements. * Its hasNext() returns always false, * next() throws a NoSuchElementException * and remove() throws an IllegalStateException. * Note that the Collections.emptyIterable() static method is introduced by Java 7. * @param the element type, irrelevant * @return the iterable */ @SuppressWarnings("unchecked") public static Iterable empty() { return (Iterable)EMPTY_ITERABLE; } /** * Creates an iterable sequence which returns all elements from source * followed by the supplied value as last. *

The returned iterable forwards all {@code remove()} * methods to the source iterable, except the last element where it * throws UnsupportedOperationException.

* @param the element type * @param source the source sequence * @param value the value to append * @return the new iterable */ public static Iterable endWith( final Iterable source, T value) { return concat(source, just(value)); } /** * Compare two object in a null-safe manner. * @param a the first object * @param b the second object * @return true if both are null or equal according to Object.equals */ private static boolean equal(Object a, Object b) { return (a == b) || ((a != null) && a.equals(b)); } /** * Creates an onError notification. * @param the value type * @param t the throwable * @return the notification */ static Notification err(Throwable t) { return Notification.createOnError(t); } /** * Returns an iterable which executes the given action after * the stream completes. *

The returned iterator forwards all remove() calls * to the source.

* @param the element type * @param source the source of Ts * @param action the action to invoke * @return the new iterable */ public static Iterable doOnCompleted( final Iterable source, final Action0 action) { return new DoOnCompletedIterable(action, source); } /** * Returns the first element from the iterable sequence or * throws a NoSuchElementException. * @param the value type * @param src the source sequence * @return the first element */ public static T first(Iterable src) { Iterator itor = src.iterator(); try { return itor.next(); } finally { unsubscribe(itor); } } /** * Returns the first element from the sequence or the default * value if this sequence is empty * @param the value type * @param src the source sequence * @param defaultValue the default value to return * @return the first or default value * @since 0.91.2 */ public static T firstOrDefault(Iterable src, T defaultValue) { Iterator itor = src.iterator(); try { if (itor.hasNext()) { return itor.next(); } return defaultValue; } finally { Interactive.unsubscribe(itor); } } /** * Returns an iterable which runs the source iterable and * returns elements from the iterable returned by the function call. * The difference from flatMap is that the {@code Iterable<U>}s are * created before their concatenation starts. * @param the source element type * @param the output element type * @param source the source * @param selector the result selector * @return the new iterable */ public static Iterable flatMapAll( final Iterable source, final Func1> selector) { return concat(map(source, selector)); } /** * Iterate over the source and submit each value to the * given action. Basically, a for-each loop with pluggable * action. * This method is useful when the concrete values from the iterator * are not needed but the iteration itself implies some side effects. * @param the element type of the iterable * @param source the iterable * @param action the action to invoke on with element */ public static void forEach( final Iterable source, Action1 action) { Iterator iter = source.iterator(); try { while (iter.hasNext()) { T t = iter.next(); action.call(t); } } finally { unsubscribe(iter); } } /** * A generator function which returns Ts based on the termination condition and the way it computes the next values. * This is equivalent to: *

     * T value = seed;
     * while (predicate(value)) {
     *     yield value;
     *     value = next(value);
     * }
     * 
*

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param seed the initial value * @param predicate the predicate to terminate the process * @param next the function that computes the next value. * @return the new iterable */ public static Iterable generate( final T seed, final Func1 predicate, final Func1 next) { return new GenerateIterable(seed, next, predicate); } /** * A generator function which returns Ts based on the termination condition and the way it computes the next values, * but the first T to be returned is preceded by an initialDelay amount of wait and each * subsequent element is then generated after betweenDelay sleep. * The sleeping is blocking the current thread which invokes the hasNext()/next() methods. * This is equivalent to: *

     * T value = seed;
     * sleep(initialDelay);
     * if (predicate(value)) {
     *     yield value;
     * }
     * value = next(value);
     * sleep(betweenDelay);
     * while (predicate(value)) {
     *     yield value;
     *     value = next(value);
     *     sleep(betweenDelay);
     * }
     * 
*

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param seed the initial value * @param predicate the predicate to terminate the process * @param next the function that computes the next value. * @param initialDelay the initial delay * @param betweenDelay the between delay * @param unit the time unit for initialDelay and betweenDelay * @return the new iterable */ public static Iterable generate( final T seed, final Func1 predicate, final Func1 next, final long initialDelay, final long betweenDelay, final TimeUnit unit) { return new GenerateIterableTimed(predicate, next, seed, initialDelay, betweenDelay, unit); } /** * Creates an iterable which traverses the source iterable, * and based on the key selector, groups values of T into GroupedIterables, * which can be iterated over later on. * The equivalence of the keys are determined via reference * equality and equals() equality. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the result group keys * @param source the source of Ts * @param keySelector the key selector * @return the new iterable */ public static Iterable> groupBy( final Iterable source, final Func1 keySelector ) { return groupBy(source, keySelector, IxHelperFunctions.identity()); } /** * Creates an iterable which traverses the source iterable, * and based on the key selector, groups values extracted by valueSelector into GroupedIterables, * which can be iterated over later on. * The equivalence of the keys are determined via reference * equality and equals() equality. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the result group element type * @param the result group keys * @param source the source of Ts * @param keySelector the key selector * @param valueSelector the value selector * @return the new iterable */ public static Iterable> groupBy( final Iterable source, final Func1 keySelector, final Func1 valueSelector) { return distinct(new Iterable>() { @Override public Iterator> iterator() { final Map> groups = new LinkedHashMap>(); final Iterator it = source.iterator(); return new Iterator>() { Iterator> groupIt; @Override public boolean hasNext() { return it.hasNext() || (groupIt != null && groupIt.hasNext()); } @Override public GroupedIterable next() { if (hasNext()) { if (groupIt == null) { try { while (it.hasNext()) { T t = it.next(); V v = keySelector.call(t); U u = valueSelector.call(t); GroupedIterable g = groups.get(v); if (g == null) { g = new GroupedIterable(v); groups.put(v, g); } g.add(u); } } finally { unsubscribe(it); } groupIt = groups.values().iterator(); } return groupIt.next(); } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }, new Func1, V>() { @Override public V call(GroupedIterable param1) { return param1.getKey(); } }, IxHelperFunctions.>identity()); } /** * Returns an iterable which invokes the given next * action for each element and the finish action when * the source completes. * @param the source element type * @param source the source of Ts * @param next the action to invoke on each element * @param finish the action to invoke after the last element * @return the new iterable */ public static Iterable doOnEach( final Iterable source, Action1 next, Action0 finish) { return doOnEach(source, next, Actions.empty(), finish); } /** * Returns an iterable which invokes the given next * action for each element and error when an exception is thrown. * @param the source element type * @param source the source of Ts * @param next the action to invoke on each element * @param error the error action to invoke for an error * @return the new iterable */ public static Iterable doOnEach( final Iterable source, final Action1 next, final Action1 error) { return doOnEach(source, next, error, Actions.empty()); } /** * Returns an iterable which invokes the given next * action for each element and the finish action when * the source completes and error when an exception is thrown. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param source the source of Ts * @param next the action to invoke on each element * @param error the error action to invoke for an error * @param finish the action to invoke after the last element * @return the new iterable */ public static Iterable doOnEach( final Iterable source, final Action1 next, final Action1 error, final Action0 finish) { return new DoOnEachIterable(error, finish, source); } /** * Returns a single true if the target iterable is empty. * @param source source iterable with any type * @return the new iterable */ public static Iterable isEmpty( final Iterable source) { return map(any(source), IxHelperFunctions.negate()); } /** * Concatenates the source strings one after another and uses the given separator. *

The returned iterator forwards all remove() calls * to the source.

* @param source the source * @param separator the separator to use * @return the new iterable */ public static Iterable join( final Iterable source, final String separator) { return aggregate(source, new Func2() { @Override public StringBuilder call(StringBuilder param1, Object param2) { if (param1 == null) { param1 = new StringBuilder(); } else { param1.append(separator); } param1.append(param2); return param1; } }, new Func2() { @Override public String call(StringBuilder param1, Integer param2) { return param1.toString(); } } ); } /** * Returns the last element of the iterable or throws a NoSuchElementException if the iterable is empty. * @param the source element type * @param source the source of Ts * @return the last value */ public static T last( final Iterable source) { Iterator it = source.iterator(); try { if (it.hasNext()) { T t; do { t = it.next(); } while (it.hasNext()); return t; } } finally { unsubscribe(it); } throw new NoSuchElementException(); } /** * Returns the last element of this sequence or the default value if * this sequence is empty. * @param the source element type * @param source the source of Ts * @param defaultValue the default value to return if this sequence is empty * @return the last value */ public static T lastOrDefault( final Iterable source, T defaultValue) { Iterator it = source.iterator(); try { if (it.hasNext()) { T t; do { t = it.next(); } while (it.hasNext()); return t; } return defaultValue; } finally { unsubscribe(it); } } /** * Creates an iterable which is a transforms the source * elements by using the selector function. * The function receives the current index and the current element. * @param the source element type * @param the output element type * @param source the source iterable * @param selector the selector function * @return the new iterable */ public static Iterable map( final Iterable source, final Func1 selector) { return mapIndexed(source, new Func2() { @Override public U call(Integer param1, T param2) { return selector.call(param2); } }); } /** * Creates an iterable which is a transforms the source * elements by using the selector function. * The function receives the current index and the current element. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param the output element type * @param source the source iterable * @param selector the selector function * @return the new iterable */ public static Iterable mapIndexed( final Iterable source, final Func2 selector) { return new MapIndexedIterable(source, selector); } /** * Transforms the sequence of the source iterable into an option sequence of * Notification.some(), Notification.none() and Notification.error() values, depending on * what the source's hasNext() and next() produces. * The returned iterator will throw an UnsupportedOperationException for its remove() method. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param source the source of at least Ts. * @return the new iterable */ public static Iterable> materialize( final Iterable source) { return new MaterializeIterable(source); } /** * Returns the maximum value of the given iterable source. * @param the element type, which must be self comparable * @param source the source elements * @return the new iterable */ public static > Iterable max( final Iterable source) { return aggregate(source, IxHelperFunctions.max(), IxHelperFunctions.identityFirst()); } /** * Returns the maximum value of the given iterable source in respect to the supplied comparator. * @param the element type, which must be self comparable * @param source the source elements * @param comparator the comparator to use * @return the new iterable */ public static Iterable max( final Iterable source, final Comparator comparator) { return aggregate(source, IxHelperFunctions.max(comparator), IxHelperFunctions.identityFirst()); } /** * Returns an iterator which will produce a single List of the maximum values encountered * in the source stream based on the supplied key selector. * @param the source element type, which must be self comparable * @param source the source of Ts * @return the new iterable */ public static > Iterable> maxBy( final Iterable source) { return minMax(source, IxHelperFunctions.identity(), IxHelperFunctions.comparator(), true); } /** * Returns an iterator which will produce a single List of the maximum values encountered * in the source stream based on the supplied comparator. * @param the source element type * @param source the source of Ts * @param comparator the key comparator * @return the new iterable */ public static Iterable> maxBy( final Iterable source, final Comparator comparator) { return minMax(source, IxHelperFunctions.identity(), comparator, true); } /** * Returns an iterator which will produce a single List of the maximum values encountered * in the source stream based on the supplied key selector. * @param the source element type * @param the key type, which must be self-comparable * @param source the source of Ts * @param keySelector the selector for keys * @return the new iterable */ public static > Iterable> maxBy( final Iterable source, final Func1 keySelector) { return minMax(source, keySelector, IxHelperFunctions.comparator(), true); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied key selector and comparator. * @param the source element type * @param the key type * @param source the source of Ts * @param keySelector the selector for keys * @param keyComparator the key comparator * @return the new iterable */ public static Iterable> maxBy( final Iterable source, final Func1 keySelector, final Comparator keyComparator) { return minMax(source, keySelector, keyComparator, true); } /** * Enumerates the source iterable once and caches its results. * Any iterator party will basically drain this cache, e.g., * reiterating over this iterable will produce no results. * Note: the name is not a misspelling, see Memoization. * FIXME not sure about the buffer sizes. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param source the source of Ts * @param bufferSize the size of the buffering * @return the new iterable */ public static Iterable memoize( final Iterable source, final int bufferSize) { if (bufferSize < 0) { throw new IllegalArgumentException("bufferSize < 0"); } return new MemoizeIterable(source, bufferSize); } /** * The returned iterable ensures that the source iterable is only traversed once, regardless of * how many iterator attaches to it and each iterator see only the values. * Note: the name is not a misspelling, see Memoization. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param source the source of Ts * @return the new iterable */ public static Iterable memoizeAll( final Iterable source) { final Iterator it = source.iterator(); final LinkedBuffer buffer = new LinkedBuffer(); return new MemoizeAllIterable(it, buffer); } /** * Merges a bunch of iterable streams where each of the iterable will run by * a scheduler and their events are merged together in a single stream. * The returned iterator throws an UnsupportedOperationException in its remove() method. * @param the element type * @param sources the iterable of source iterables. * @return the new iterable */ public static Iterable merge( final Iterable> sources) { return merge(sources, scheduler()); } /** * Merges a bunch of iterable streams where each of the iterable will run by * a scheduler and their events are merged together in a single stream. * The returned iterator throws an UnsupportedOperationException in its remove() method. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param sources the iterable of source iterables. * @param scheduler the scheduler for running each inner iterable in parallel * @return the new iterable */ public static Iterable merge( final Iterable> sources, final Scheduler scheduler) { return new MergeIterable(scheduler, sources); } /** * Merges two iterable streams. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param first the first iterable * @param second the second iterable * @return the resulting stream of Ts */ public static Iterable merge( final Iterable first, final Iterable second) { List> list = new ArrayList>(2); list.add(first); list.add(second); return merge(list); } /** * Returns the minimum value of the given iterable source. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type, which must be self comparable * @param source the source elements * @return the new iterable */ public static > Iterable min( final Iterable source) { return aggregate(source, IxHelperFunctions.min(), IxHelperFunctions.identityFirst()); } /** * Returns the minimum value of the given iterable source in respect to the supplied comparator. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type, which must be self comparable * @param source the source elements * @param comparator the comparator to use * @return the new iterable */ public static Iterable min( final Iterable source, final Comparator comparator) { return aggregate(source, IxHelperFunctions.min(comparator), IxHelperFunctions.identityFirst()); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied key selector. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type, which must be self comparable * @param source the source of Ts * @return the new iterable */ public static > Iterable> minBy( final Iterable source) { return minMax(source, IxHelperFunctions.identity(), IxHelperFunctions.comparator(), false); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied comparator. * @param the source element type * @param source the source of Ts * @param comparator the key comparator * @return the new iterable */ public static Iterable> minBy( final Iterable source, final Comparator comparator) { return minMax(source, IxHelperFunctions.identity(), comparator, false); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied key selector. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the key type, which must be self-comparable * @param source the source of Ts * @param keySelector the selector for keys * @return the new iterable */ public static > Iterable> minBy( final Iterable source, final Func1 keySelector) { return minMax(source, keySelector, IxHelperFunctions.comparator(), false); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied key selector and comparator. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the key type * @param source the source of Ts * @param keySelector the selector for keys * @param keyComparator the key comparator * @return the new iterable */ public static Iterable> minBy( final Iterable source, final Func1 keySelector, final Comparator keyComparator) { return minMax(source, keySelector, keyComparator, false); } /** * Returns an iterator which will produce a single List of the minimum values encountered * in the source stream based on the supplied key selector and comparator. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the key type * @param source the source of Ts * @param keySelector the selector for keys * @param keyComparator the key comparator * @param max should the computation return the minimums or the maximums * @return the new iterable */ static Iterable> minMax( final Iterable source, final Func1 keySelector, final Comparator keyComparator, final boolean max) { return new MinMaxIterable(keySelector, source, max, keyComparator); } /** * Wraps the given source sequence into a CloseableIterable instance * where the inner CloseableIterator.close() method calls the supplied action. * @param the element type * @param src the source sequence * @param close the close action. * @return the new closeable iterable */ public static CloseableIterable newCloseableIterable( final Iterable src, final Action0 close ) { return new CloseableIterable() { @Override public CloseableIterator iterator() { return newCloseableIterator(src.iterator(), close); } }; } /** * Wraps the given source sequence into a CloseableIterable instance * where the inner CloseableIterator.close() method calls the supplied action. * @param the element type * @param src the source sequence * @param close the close action. * @return the new closeable iterable */ public static CloseableIterable newCloseableIterable( final Iterable src, final Action1> close ) { return new CloseableIterable() { @Override public CloseableIterator iterator() { return newCloseableIterator(src.iterator(), close); } }; } /** * Wraps the given source sequence into a CloseableIterable instance * where the inner CloseableIterator.close() method calls the supplied closeable object. * @param the element type * @param src the source sequence * @param close the closeable object. * @return the new closeable iterable */ public static CloseableIterable newCloseableIterable( final Iterable src, final Closeable close ) { return new CloseableIterable() { @Override public CloseableIterator iterator() { return newCloseableIterator(src.iterator(), close); } }; } /** * Wraps the supplied iterator into a CloseableIterator which calls the supplied * close action. * @param the element type * @param src the source iterator * @param close the close action * @return the new closeable iterator */ public static CloseableIterator newCloseableIterator( final Iterator src, final Action0 close ) { return new CloseableIterator() { final AtomicBoolean once = new AtomicBoolean(); @Override public boolean hasNext() { return src.hasNext(); } @Override public boolean isUnsubscribed() { return once.get(); } @Override public T next() { return src.next(); } @Override public void remove() { src.remove(); } @Override public void unsubscribe() { if (once.compareAndSet(false, true)) { close.call(); } } }; } /** * Wraps the supplied iterator into a CloseableIterator which calls the supplied * close action with the given source iterator object. * @param the element type * @param src the source iterator * @param close the close action * @return the new closeable iterator */ public static CloseableIterator newCloseableIterator( final Iterator src, final Action1> close ) { return new CloseableIterator() { final AtomicBoolean once = new AtomicBoolean(); @Override public boolean hasNext() { return src.hasNext(); } @Override public boolean isUnsubscribed() { return once.get(); } @Override public T next() { return src.next(); } @Override public void remove() { src.remove(); } @Override public void unsubscribe() { if (once.compareAndSet(false, true)) { close.call(src); } } }; } /** * Wraps the supplied iterator into a CloseableIterator which calls the supplied * closeable instance. * @param the element type * @param src the source iterator * @param close the closeable instance * @return the new closeable iterator */ public static CloseableIterator newCloseableIterator( final Iterator src, final Closeable close ) { return new CloseableIterator() { final AtomicBoolean once = new AtomicBoolean(); @Override public boolean hasNext() { return src.hasNext(); } @Override public boolean isUnsubscribed() { return once.get(); } @Override public T next() { return src.next(); } @Override public void remove() { src.remove(); } @Override public void unsubscribe() { if (once.compareAndSet(false, true)) { try { close.close(); } catch (IOException ex) { //ignored } } } }; } /** * Creates a new iterable sequence by wrapping the given function to * provide the iterator. * @param the element type * @param the iterator type * @param body the body function returning an iterator * @return the iterable sequence */ public static > Iterable newIterable( final Func0 body) { return new Iterable() { @Override public Iterator iterator() { return body.call(); } }; } /** * A functional way of creating a new iterator from the supplied * hasNext and next callbacks. *

The returned iterator throws a UnsupportedOperationException * in its remove method.

* @param the element type * @param hasNext function that returns true if more elements are available. * @param next function that returns the next element * @return the created iterator */ public static Iterator newIterator( final Func0 hasNext, final Func0 next) { return new Iterator() { @Override public boolean hasNext() { return hasNext.call(); } @Override public T next() { return next.call(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } /** * Constructs an iterator instance by wrapping the supplied functions * into the same-named iterator methods. * @param the element type * @param hasNext function that returns true if more elements are available. * @param next function that returns the next element * @param remove function to remove the current element * @return the created iterator */ public static Iterator newIterator( final Func0 hasNext, final Func0 next, final Action0 remove ) { return new Iterator() { @Override public boolean hasNext() { return hasNext(); } @Override public T next() { return next.call(); } @Override public void remove() { remove.call(); } }; } /** * Creates an onCompleted notification. * @param the value type * @return the notification */ static Notification none() { return Notification.createOnCompleted(); } /** * Casts the source iterable into a different type by using a type token. * If the source contains a wrong element, the next() * will throw a ClassCastException. *

The returned iterator forwards all remove() calls * to the source.

* @param the result element type * @param source the arbitrary source * @param token the type token * @return the new iterable */ public static Iterable ofType( final Iterable source, final Class token) { return new CastIterable(source, token); } /** * Creates an iterable which if iterates over the source and encounters an exception, * the iteration is continued on the new iterable returned by the handler function. *

The returned iterator forwards all remove() calls * to the source.

* @param the element type * @param source the source iterable. * @param handler the exception handler. * @return the new iterable */ public static Iterable onErrorResumeNext( final Iterable source, final Func1> handler) { return new OnErrorResumeNextIterable(source, handler); } /** * Creates an iterable which if iterates over the source and encounters an exception, it simply stops the iteration, consuming the exception. * @param the element type * @param source the source iterable. * @return the new iterable */ public static Iterable onErrorTerminate( final Iterable source) { Iterable e = empty(); return onErrorResumeNext(source, IxHelperFunctions.constant(e)); } /** * Returns an iterable which traverses the entire * source iterable and creates an ordered list * of elements. Once the source iterator completes, * the elements are streamed to the output. * @param the source element type, must be self comparable * @param source the source of Ts * @return the new iterable */ public static > Iterable orderBy( final Iterable source ) { return orderBy(source, IxHelperFunctions.identity(), IxHelperFunctions.comparator()); } /** * Returns an iterable which traverses the entire * source iterable and creates an ordered list * of elements. Once the source iterator completes, * the elements are streamed to the output. * @param the source element type, must be self comparable * @param source the source of Ts * @param comparator the value comparator * @return the new iterable */ public static Iterable orderBy( final Iterable source, final Comparator comparator ) { return orderBy(source, IxHelperFunctions.identity(), comparator); } /** * Returns an iterable which traverses the entire * source iterable and creates an ordered list * of elements. Once the source iterator completes, * the elements are streamed to the output. * @param the source element type * @param the key type for the ordering, must be self comparable * @param source the source of Ts * @param keySelector the key selector for comparison * @return the new iterable */ public static > Iterable orderBy( final Iterable source, final Func1 keySelector ) { return orderBy(source, keySelector, IxHelperFunctions.comparator()); } /** * Returns an iterable which traverses the entire * source iterable and creates an ordered list * of elements. Once the source iterator completes, * the elements are streamed to the output. * @param the source element type * @param the key type for the ordering * @param source the source of Ts * @param keySelector the key selector for comparison * @param keyComparator the key comparator function * @return the new iterable */ public static Iterable orderBy( final Iterable source, final Func1 keySelector, final Comparator keyComparator ) { return new OrderByIterable(source, keyComparator, keySelector); } /** * Creates an observer with debugging purposes. * It prints the submitted values to STDOUT separated by commas and line-broken by 80 characters, the exceptions to STDERR * and prints an empty newline when it receives a finish(). * @param the value type * @return the observer */ public static Action1 print() { return print(", ", 80); } /** * Creates an observer with debugging purposes. * It prints the submitted values to STDOUT, the exceptions to STDERR * and prints an empty newline when it receives a finish(). * @param the value type * @param separator the separator to use between subsequent values * @param maxLineLength how many characters to print into each line * @return the observer */ public static Action1 print(final String separator, final int maxLineLength) { return new PrintAction1(separator, maxLineLength); } /** * Creates an action for debugging purposes. * It prints the submitted values to STDOUT with a line break. * @param the value type * @return the observer */ public static Action1 println() { return new Action1() { @Override public void call(T value) { System.out.println(value); } }; } /** * Creates an action for debugging purposes. * It prints the submitted values to STDOUT with a line break. * @param the value type * @param prefix the prefix to use when printing * @return the action */ public static Action1 println(final String prefix) { return new Action1() { @Override public void call(T value) { System.out.print(prefix); System.out.println(value); } }; } /** * Applies the func function for a shared instance of the source, * e.g., func.call(share(source)). * @param the source element type * @param the return types * @param source the source of Ts * @param func invoke the function on the buffering iterable and return an iterator over it. * @return the new iterable */ public static Iterable prune( final Iterable source, final Func1, ? extends Iterable> func) { return func.call(share(source)); } /** * The returned iterable ensures that the source iterable is only traversed once, regardless of * how many iterator attaches to it and each iterator see only the same cached values. *

The returned iterator will throw an UnsupportedOperationException * for remove() method of its first element, then it might throw for any * subsequent element, depending on the source iterable.

* @param the source element type * @param the return types * @param source the source of Ts * @param func invoke the function on the buffering iterable and return an iterator over it. * @param initial the initial value to append to the output stream * @return the new iterable */ @SuppressWarnings("unchecked") public static Iterable publish( final Iterable source, final Func1, ? extends Iterable> func, final U initial) { return startWith(func.call(memoizeAll(source)), initial); } /** * The returned iterable ensures that the source iterable is only traversed once, regardless of * how many iterator attaches to it and each iterator see only the values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the return types * @param source the source of Ts * @param func invoke the function on the buffering iterable and return an iterator over it. * @return the new iterable * TODO check */ public static Iterable publish( final Iterable source, final Func1, ? extends Iterable> func) { return func.call(memoizeAll(source)); } /** * Creates an integer iterator which returns numbers from the start position in the count size. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param start the starting value. * @param count the number of elements to return, negative count means counting down from the start. * @return the iterator. */ public static Iterable range(final int start, final int count) { return new RangeIterable(start, count); } /** * Creates an long iterator which returns numbers from the start position in the count size. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param start the starting value. * @param count the number of elements to return, negative count means counting down from the start. * @return the iterator. */ public static Iterable range(final long start, final long count) { return new LongRangeIterable(start, count); } /** * Relays the source iterable's values until the gate returns false. * @param the source element type * @param source the source of Ts * @param gate the gate to stop the relaying * @return the new iterable */ public static Iterable relayWhile( final Iterable source, final Func0 gate) { return filterIndexed(source, new Func0>() { @Override public Func2 call() { return new Func2() { /** The activity checker which turns to false once the gate returns false. */ boolean active = true; @Override public Boolean call(Integer param1, T param2) { active &= gate.call(); return active; } }; } }); } /** * Creates an iterable sequence which returns the given value indefinitely. *

(E.g., having the hasNext() always return true and the next() always return the value.

*

The returned iterable does not support the {@code remove()} method.

* @param the value type * @param value the value to repeat * @return the iterable */ public static Iterable repeat(final T value) { return new RepeatIterable(value); } /** * Returns an iterable which repeats the given single value the specified number of times. *

The returned iterable does not support the {@code remove()} method.

* @param the value type * @param value the value to repeat * @param count the repeat amount * @return the iterable */ public static Iterable repeat(final T value, final int count) { return new RepeatCountIterable(count, value); } /** * The returned iterable ensures that the source iterable is only traversed once, regardless of * how many iterator attaches to it and each iterator may only see one source element. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the return types * @param source the source of Ts * @param func invoke the function on the buffering iterable and return an iterator over it. * @return the new iterable */ public static Iterable replay( final Iterable source, final Func1, ? extends Iterable> func) { return func.call(memoize(source, 0)); } /** * The returned iterable ensures that the source iterable is only traversed once, regardless of * how many iterator attaches to it and each iterator see only the some cached values. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the source element type * @param the return types * @param source the source of Ts * @param func invoke the function on the buffering iterable and return an iterator over it. * @param bufferSize the buffer size * @return the new iterable */ public static Iterable replay( final Iterable source, final Func1, ? extends Iterable> func, final int bufferSize) { return func.call(memoize(source, bufferSize)); } /** * Creates an iterable which resumes with the next iterable from the sources when one throws an exception or completes normally. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param sources the list of sources to try one after another * @return the new iterable */ public static Iterable onErrorResumeNext( final Iterable> sources) { return new OnErrorResumeNext(sources); } /** * Creates an iterable which resumes with the next iterable from the sources when one throws an exception. * @param the source element type * @param first the first source * @param second the second source * @return the new iterable */ public static Iterable onErrorResumeNext( final Iterable first, final Iterable second) { List> list = new ArrayList>(2); list.add(first); list.add(second); return onErrorResumeNext(list); } /** * Creates an iterator which attempts to re-iterate the source if it threw an exception. *

     * while (count-- > 0) {
     * 	  try {
     *        for (T t : source) {
     *            yield t;
     *        }
     *        break;
     *    } catch (Throwable t) {
     *        if (count <= 0) {
     *            throw t;
     *        }
     *    }
     * }
     * 
*

The returned iterator forwards all remove() calls * to the source.

* @param the source type * @param source the source of Ts * @param count the number of retry attempts * @return the new iterable */ public static Iterable retry( final Iterable source, final int count) { return new RetryIterable(count, source); } /** * Iterates over the given source without using its returned value. * This method is useful when the concrete values from the iterator * are not needed but the iteration itself implies some side effects. * @param source the source iterable to run through */ public static void run( final Iterable source) { forEach(source, Actions.empty()); } /** * Generates an iterable which acts like a running sum when iterating over the source iterable, e.g., * For each element in T, it computes a value by using the current aggregation value and returns it. * The first call to the aggregator function will receive a zero for its first argument. * @param the source element type * @param the destination element type * @param source the source of Ts * @param aggregator the function which takes the current running aggregation value, the current element and produces a new aggregation value. * @return the new iterable * TODO rework */ public static Iterable scan( final Iterable source, final Func2 aggregator) { return scan(source, null, aggregator); } /** * Generates an iterable which acts like a running sum when iterating over the source iterable, e.g., * For each element in T, it computes a value by using the current aggregation value and returns it. * The first call to the aggregator function will receive a zero for its first argument. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param the destination element type * @param source the source of Ts * @param seed the initial value of the running aggregation * @param aggregator the function which takes the current running aggregation value, the current element and produces a new aggregation value. * @return the new iterable */ public static Iterable scan( final Iterable source, final U seed, final Func2 aggregator) { return new ScanIterable(source, aggregator, seed); } /** * @return the current default pool used by the Observables methods */ static Scheduler scheduler() { return Schedulers.computation(); } /** * Creates an iterable which returns a stream of Us for each source Ts. * The iterable stream of Us is returned by the supplied selector function. *

The returned iterator forwards all remove() calls * to the current source (which might not accept it). * @param the source element type * @param the output element type * @param source the source * @param selector the selector for multiple Us for each T * @return the new iterable */ public static Iterable flatMap( final Iterable source, final Func1> selector) { return new FlatMapIterable(selector, source); } /** * Returns an iterable which ensures the source iterable is * only traversed once and clients may take values from each other, * e.g., they share the same iterator. * @param the source element type * @param source the source iterable * @return the new iterable */ public static Iterable share( final Iterable source) { return new ShareIterable(source); } /** * Shares the source sequence within the specified * selector function where each iterator can fetch * the next element from the source. * @param the source element type * @param the result element type * @param source the source sequence * @param selector the selector function * @return the new iterable * TODO Builder */ public static Iterable share( final Iterable source, final Func1, ? extends Iterable> selector ) { return new ShareSelectorIterable(source, selector); } /** * Creates an iterable which returns only a single element. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param value the value to return * @return the new iterable */ public static Iterable just(final T value) { return new JustIterable(value); } /** * Immediately returns the number of elements in {@code iterable}. * @param iterable the input sequence * @return the number of elements in the sequence */ public static int size(Iterable iterable) { return first(count(iterable)); } /** * Skips the specified amount of items at the beginning of the source sequence. * @param the element type * @param source the source iterable * @param num the number of elements to skip * @return the new iterable */ public static Iterable skip(final Iterable source, final int num) { return new Skip(source, num); } /** * Returns an iterable which skips the last num elements from the * source iterable. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @param num the number of elements to skip at the end * @return the new iterable */ public static Iterable skipLast( final Iterable source, final int num) { return new SkipLastIterable(source, num); } /** * Creates an onNext notification. * @param the value type * @param value the value to wrap * @return the notification */ static Notification some(T value) { return Notification.createOnNext(value); } /** * Returns an iterable which prefixes the source iterable values * by a constant. * It is equivalent to concat(singleton(value), source). *

The returned iterator will throw an UnsupportedOperationException * for its remove() method for the first element, and might * throw for subsequent elements, depending on the source iterable.

* @param the element type * @param source the source iterable * @param value the value to prefix * @return the new iterable. */ public static Iterable startWith( Iterable source, final T... value) { return concat(Arrays.asList(value), source); } /** * Creates an iterable which returns two subsequent items from the source * iterable as pairs of values. If the {@code source} contains zero or one elements, this * iterable will be empty. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @return the new iterable */ public static Iterable> subsequent(final Iterable source) { return new SubsequentIterable(source); } /** * Creates an iterable which returns {@code count} subsequent items from the source * iterable as sequence of values. * If the {@code source} contains less than {@code count} elements, this * iterable will be empty. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @param count the element count * @return the new iterable */ public static Iterable> subsequent( final Iterable source, final int count) { if (count <= 0) { throw new IllegalArgumentException("Count must be > 0"); } if (count == 1) { return map(source, new Func1>() { @Override public Iterable call(T param1) { return just(param1); } }); } return new SubsequentCountIterable(source, count); } /** * Sum the source of Integer values and return it as a single element. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source * @return the new iterable */ public static Iterable sumBigDecimal( Iterable source) { return aggregate(source, IxHelperFunctions.sumBigDecimal(), IxHelperFunctions.identityFirst() ); } /** * Sum the source of Integer values and return it as a single element. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source * @return the new iterable */ public static Iterable sumBigInteger( Iterable source) { return aggregate(source, IxHelperFunctions.sumBigInteger(), IxHelperFunctions.identityFirst() ); } /** * Sum the source of Double values and returns it as a single element. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param source the source * @return the new iterable */ public static Iterable sumDouble( Iterable source) { return aggregate(source, IxHelperFunctions.sumDouble(), IxHelperFunctions.identityFirst() ); } /** * Sum the source of Float values and returns it as a single element. * @param source the source * @return the new iterable */ public static Iterable sumFloat( Iterable source) { return aggregate(source, IxHelperFunctions.sumFloat(), IxHelperFunctions.identityFirst() ); } /** * Sum the source of Integer values and returns it as a single element. * @param source the source * @return the new iterable */ public static Iterable sumInt( Iterable source) { return aggregate(source, IxHelperFunctions.sumInteger(), IxHelperFunctions.identityFirst() ); } /** * Computes and signals the sum of the values of the Integer source by using * a double intermediate representation. * The source may not send nulls. An empty source produces an empty sum * @param source the source of integers to aggregate. * @return the observable for the sum value */ public static Iterable sumIntAsDouble( final Iterable source) { return aggregate(source, new Func2() { @Override public Double call(Double param1, Integer param2) { return param1 + param2; } }, IxHelperFunctions.identityFirst() ); } /** * Sum the source of Long values and returns it as a single element. * @param source the source * @return the new iterable */ public static Iterable sumLong( Iterable source) { return aggregate(source, IxHelperFunctions.sumLong(), IxHelperFunctions.identityFirst() ); } /** * Computes and signals the sum of the values of the Long sourceby using * a double intermediate representation. * The source may not send nulls. * @param source the source of longs to aggregate. * @return the observable for the sum value */ public static Iterable sumLongAsDouble( final Iterable source) { return aggregate(source, new Func2() { @Override public Double call(Double param1, Long param2) { return param1 + param2; } }, IxHelperFunctions.identityFirst() ); } /** * Returns an iterable, which will query the selector for a key, then * queries the map for an Iterable. The returned iterator will * then traverse that Iterable. If the map does not contain an * element, az empty iterable is used. * @param the key type * @param the output type * @param selector the key selector * @param options the available options in * @return the new iterable */ public static Iterable switchCase( final Func0 selector, final Map> options) { return new SwitchCaseIterable(selector, options); } /** * Returns the iterable which returns the first num element. * from the source iterable. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param source the source of Ts * @param num the number of items to take * @return the new iterable */ public static Iterable take( final Iterable source, final int num) { return new TakeIterable(num, source); } /** * Returns an iterable which takes only the last num elements from the * source iterable. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param source the source iterable * @param num the number of elements to skip at the end * @return the new iterable */ public static Iterable takeLast( final Iterable source, final int num) { return new TakeLastIterable(source, num); } /** * Returns an iterator which will throw the given * Throwable exception when the client invokes * next() the first time. Any subsequent * next() call will simply throw a NoSuchElementException. * Calling remove() will always throw a IllegalStateException. * If the given Throwable instance extends a RuntimeException, it is throws * as is, but when the throwable is a checked exception, it is wrapped * into a RuntimeException. * @param the element type, irrelevant * @param t the exception to throw * @return the new iterable */ public static Iterable error( final Throwable t) { return new ErrorIterable(t); } /** * Convert the source Iterable into the Enumerable semantics. * @param the source element type * @param e the iterable * @return the new enumerable */ public static Enumerable toEnumerable( final Iterable e) { return new Enumerable() { @Override public Enumerator enumerator() { return toEnumerator(e.iterator()); } }; } /** * Convert the given iterator to the Enumerator semantics. * @param the element type * @param it the source iterator * @return the new enumerator */ public static Enumerator toEnumerator( final Iterator it) { return new IteratorToEnumerator(it); } /** * Convert the source enumerable into the Iterable semantics. * @param the source element type * @param e the enumerable * @return the new iterable */ public static Iterable toIterable( final Enumerable e) { return new Iterable() { @Override public Iterator iterator() { return toIterator(e.enumerator()); } }; } /** * Takes the input elements and returns an iterable which * traverses the array. The supplied array is * shared by the iterator. Any changes to the array will be * reflected by the iterator *

The resulting {@code Iterable} does not support {@code remove()}.

* @param the element type * @param ts the input array * @return the iterable for the array */ public static Iterable toIterable(final T... ts) { return new Iterable() { @Override public Iterator iterator() { return new Iterator() { /** The current location. */ int index; /** The lenght. */ final int size = ts.length; @Override public boolean hasNext() { return index < size; } @Override public T next() { if (hasNext()) { return ts[index++]; } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } /** * Takes the input elements and returns an iterable which * traverses the array between the two indexes. The supplied array is * shared by the iterator. Any changes to the array will be * reflected by the iterator. *

The resulting {@code Iterable} does not support {@code remove()}.

* @param the element type * @param from the starting index inclusive * @param to the end index exclusive * @param ts the input array * @return the iterable for the array */ public static Iterable toIterablePart( final int from, final int to, final T... ts) { return new PartialIterable(from, ts, to); } /** * Convert the given enumerator to the Iterator semantics. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the element type * @param en the source enumerator * @return the new iterator */ public static Iterator toIterator( final Enumerator en) { return new EnumerationToIterator(en); } /** * Call unsubscribe on the iterator if it implements the Subscription interface. * @param iter the iterator to unsubscribe */ public static void unsubscribe(Iterator iter) { if (iter instanceof Subscription) { ((Subscription)iter).unsubscribe(); } } /** * Returns an iterable which is associated with a closeable handler. * Once the source iterable is completed, it invokes the Closeable.close() on the handler. *

The returned iterator forwards all remove() calls * to the source.

* @param the source element type * @param the closeable type * @param resource the function which returns a resource token * @param usage the function which gives an iterable for a resource token. * @return the new iterable */ public static Iterable using( final Func0 resource, final Func1> usage) { return new UsingIterable(resource, usage); } /** * Extracts the notification value, exception or throws NoSuchElementException. * @param the value type * @param notif the notification to extract from * @return the value */ static T value(Notification notif) { if (notif.isOnNext()) { return notif.getValue(); } else if (notif.isOnError()) { Exceptions.propagate(notif.getThrowable()); } throw new NoSuchElementException(); } /** * Creates an iterable which filters the source iterable with the * given predicate factory function. The predicate returned by the factory receives an index * telling how many elements were processed thus far. * Use this construct if you want to use some memorizing predicate function (e.g., filter by subsequent distinct, filter by first occurrences only) * which need to be invoked per iterator() basis. *

The returned iterator forwards all remove() calls * to the source.

* @param the element type * @param source the source iterable * @param predicateFactory the predicate factory which should return a new predicate function for each iterator. * @return the new iterable */ public static Iterable filterIndexed( final Iterable source, final Func0> predicateFactory) { return new FilterIndexedIterable(source, predicateFactory); } /** * Creates an iterable which filters the source iterable with the * given predicate function. The predicate receives the value and * must return a boolean whether to accept that entry. * @param the element type * @param source the source iterable * @param predicate the predicate function * @return the new iterable */ public static Iterable filter( final Iterable source, final Func1 predicate) { return filterIndexed(source, IxHelperFunctions.constant0(new Func2() { @Override public Boolean call(Integer param1, T param2) { return predicate.call(param2); } })); } /** * Creates an iterable which filters the source iterable with the * given predicate factory function. The predicate returned by the factory receives an index * telling how many elements were processed thus far. * @param the element type * @param source the source iterable * @param predicate the predicate * @return the new iterable */ public static Iterable filterIndexed( final Iterable source, final Func2 predicate) { return filterIndexed(source, IxHelperFunctions.constant0(predicate)); } /** * Pairs each element from both iterable sources and * combines them into a new value by using the combiner * function. *

The returned iterator will throw an UnsupportedOperationException * for its remove() method.

* @param the left source type * @param the right source type * @param the result type * @param left the left source * @param right the right source * @param combiner the combiner function * @return the new iterable */ public static Iterable zip( final Iterable left, final Iterable right, final Func2 combiner) { return new ZipIterable(left, right, combiner); } /** The common empty iterator. */ private static final Iterator EMPTY_ITERATOR = new Iterator() { @Override public boolean hasNext() { return false; } @Override public Object next() { throw new NoSuchElementException(); } @Override public void remove() { throw new IllegalStateException(); } }; /** The common empty iterable. */ private static final Iterable EMPTY_ITERABLE = new Iterable() { @Override public Iterator iterator() { return EMPTY_ITERATOR; } }; // TODO IBuffer publish(Iterable) // TODO memoize(Iterable) // TODO memoize(Iterable, Func) // TODO memoize(Iterable, int, Func) // TODO throwException(Func) // TODO catchException(Iterable>) // TODO catchException(Iterable, Iterable) // TODO retry(Iterable) // TODO resumeOnError(Iterable...) // TODO ifThen(Func, Iterable) // TODO ifThen(Func, Iterable, Iterable) // TODO whileDo(Func, Iterable) // TODO switchCase(Func, Map>, Iterable) // TODO selectMany(Iterable, Iterable) // TODO forEach(Iterable, Action) // TODO forEach(Iterable, Action) // TODO invoke(Iterable, Observer) // TODO buffer(Iterable, int, int) // TODO ignoreValues(Iterable) // TODO distinct(Iterable, Func2) // TODO distinct(Iterable, Func, Func) // TODO distinctNext(Iterable, Func, Func, Func>) // TODO repeat(Iterable) // TODO repeat(Iterable, count) /** Utility class. */ private Interactive() { // utility class } }