Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private Guavate() {
* <p>
* This is harder than it should be, a method {@code Stream.of(Iterable)}
* would have been appropriate, but cannot be added now.
*
*
* @param <T> the type of element in the iterable
* @param iterables the iterables to combine
* @return the list that combines the inputs
Expand All @@ -80,6 +80,21 @@ public static <T> ImmutableList<T> concatToList(Iterable<? extends T>... iterabl
return ImmutableList.copyOf(Iterables.concat(iterables));
}

/**
* Concatenates a number of iterables into a single set.
* <p>
* This is harder than it should be, a method {@code Stream.of(Iterable)}
* would have been appropriate, but cannot be added now.
*
* @param <T> the type of element in the iterable
* @param iterables the iterables to combine
* @return the set that combines the inputs
*/
@SafeVarargs
public static <T> ImmutableSet<T> concatToSet(Iterable<? extends T>... iterables) {
return ImmutableSet.copyOf(Iterables.concat(iterables));
}

//-------------------------------------------------------------------------
/**
* Combines two distinct maps into a single map.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import static com.opengamma.strata.collect.Guavate.concatToList;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
Expand All @@ -32,7 +34,9 @@
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import org.joda.beans.impl.direct.DirectPrivateBeanBuilder;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.ArgChecker;

/**
Expand Down Expand Up @@ -140,11 +144,13 @@ public static <T> BinaryOperator<ValueWithFailures<T>> combiningValues(BinaryOpe
}

/**
* Returns a collector that can be used to create a ValueWithFailure instance from a stream of ValueWithFailure
* instances.
* Returns a collector that can be used to create a combined {@code ValueWithFailure}
* from a stream of separate instances.
* <p>
* The {@link Collector} returned performs a reduction of its {@link ValueWithFailures} input elements under a
* specified {@link BinaryOperator} using the provided identity.
* <p>
* This collects a {@code Stream<ValueWithFailures<T>>} to a {@code ValueWithFailures<T>}.
*
* @param <T> the type of the success value in the {@link ValueWithFailures}
* @param identityValue the identity value
Expand All @@ -159,59 +165,115 @@ public static <T> BinaryOperator<ValueWithFailures<T>> combiningValues(BinaryOpe
}

/**
* Returns a collector that can be used to create a {@code ValueWithFailure} instance with a list of success values
* from a stream of {@code ValueWithFailure} instances.
* Returns a collector that creates a combined {@code ValueWithFailure} from a stream
* of separate instances, combining into an immutable list.
* <p>
* This collects a {@code Stream<ValueWithFailures<T>>} to a {@code ValueWithFailures<List<T>>}.
*
* @param <T> the type of the success value in the {@link ValueWithFailures}
* @return a {@link Collector}
*/
public static <T> Collector<ValueWithFailures<T>, ?, ValueWithFailures<ImmutableList<T>>> toCombinedValuesAsList() {
public static <T> Collector<ValueWithFailures<? extends T>, ?, ValueWithFailures<List<T>>> toCombinedValuesAsList() {
return Collector.of(
StreamBuilder<T>::new,
StreamBuilder::addSingle,
StreamBuilder::combining,
() -> new StreamBuilder<>(ImmutableList.<T>builder()),
StreamBuilder::add,
StreamBuilder::combine,
StreamBuilder::build);
}

// Utility class to help combine ValueWithFailures
private static final class StreamBuilder<T> {

private final ImmutableList.Builder<T> values = ImmutableList.builder();
private final ImmutableList.Builder<FailureItem> failures = ImmutableList.builder();

private void addSingle(ValueWithFailures<T> item) {
values.add(item.getValue());
failures.addAll(item.getFailures());
}

private StreamBuilder<T> combining(StreamBuilder<T> builder) {
values.addAll(builder.values.build());
failures.addAll(builder.failures.build());
return this;
}

private ValueWithFailures<ImmutableList<T>> build() {
return ValueWithFailures.of(values.build(), failures.build());
}
/**
* Returns a collector that creates a combined {@code ValueWithFailure} from a stream
* of separate instances, combining into an immutable set.
* <p>
* This collects a {@code Stream<ValueWithFailures<T>>} to a {@code ValueWithFailures<Set<T>>}.
*
* @param <T> the type of the success value in the {@link ValueWithFailures}
* @return a {@link Collector}
*/
public static <T> Collector<ValueWithFailures<? extends T>, ?, ValueWithFailures<Set<T>>> toCombinedValuesAsSet() {
return Collector.of(
() -> new StreamBuilder<>(ImmutableSet.<T>builder()),
StreamBuilder::add,
StreamBuilder::combine,
StreamBuilder::build);
}

/**
* Converts a list of value with failures to a single value with failures, combining the values into a list.
* Combines separate instances of {@code ValueWithFailure} into a single instance,
* using a list to collect the values.
* <p>
* Effectively, this converts {@code List<ValueWithFailures<T>>} to {@code ValueWithFailures<List<T>>}.
* This converts {@code Iterable<ValueWithFailures<T>>} to {@code ValueWithFailures<List<T>>}.
*
* @param <T> the type of the success value in the {@link ValueWithFailures}
* @param items the items to combine
* @return a new instance with a list of success values
*/
public static <T> ValueWithFailures<List<T>> combineValuesAsList(List<? extends ValueWithFailures<? extends T>> items) {
public static <T> ValueWithFailures<List<T>> combineValuesAsList(
Iterable<? extends ValueWithFailures<? extends T>> items) {

ImmutableList.Builder<T> values = ImmutableList.builder();
ImmutableList.Builder<FailureItem> failures = ImmutableList.builder();
ImmutableList<FailureItem> failures = combine(items, values);
return ValueWithFailures.of(values.build(), failures);
}

/**
* Combines separate instances of {@code ValueWithFailure} into a single instance,
* using a set to collect the values.
* <p>
* This converts {@code Iterable<ValueWithFailures<T>>} to {@code ValueWithFailures<Set<T>>}.
*
* @param <T> the type of the success value in the {@link ValueWithFailures}
* @param items the items to combine
* @return a new instance with a set of success values
*/
public static <T> ValueWithFailures<Set<T>> combineValuesAsSet(
Iterable<? extends ValueWithFailures<? extends T>> items) {

ImmutableSet.Builder<T> values = ImmutableSet.builder();
ImmutableList<FailureItem> failures = combine(items, values);
return ValueWithFailures.of(values.build(), failures);
}

// combines the collection into the specified builder
private static <T> ImmutableList<FailureItem> combine(
Iterable<? extends ValueWithFailures<? extends T>> items,
ImmutableCollection.Builder<T> values) {

ImmutableList.Builder<FailureItem> failures = ImmutableList.builder();
for (ValueWithFailures<? extends T> item : items) {
values.add(item.getValue());
failures.addAll(item.getFailures());
}
return ValueWithFailures.of(values.build(), failures.build());
return failures.build();
}

// mutable combined instance builder for use in stream collection
// using a single dedicated collector is more efficient than a reduction with multiple calls to combinedWith()
private static final class StreamBuilder<T, B extends ImmutableCollection.Builder<T>> {

private final B values;
private final ImmutableList.Builder<FailureItem> failures = ImmutableList.builder();

private StreamBuilder(B values) {
this.values = values;
}

private void add(ValueWithFailures<? extends T> item) {
values.add(item.getValue());
failures.addAll(item.getFailures());
}

private StreamBuilder<T, B> combine(StreamBuilder<T, B> builder) {
values.addAll(builder.values.build());
failures.addAll(builder.failures.build());
return this;
}

// cast to the right collection type, can assume the methods in this class are using the correct types
@SuppressWarnings("unchecked")
private <C extends Collection<T>> ValueWithFailures<C> build() {
return (ValueWithFailures<C>) ValueWithFailures.of(values.build(), failures.build());
}
}

//-------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -68,6 +69,21 @@ public void test_concatToList_differentTypes() {
assertEquals(test, ImmutableList.of(1, 2, 3, 10d, 20d, 30d));
}

//-------------------------------------------------------------------------
public void test_concatToSet() {
Iterable<String> iterable1 = Arrays.asList("a", "b", "c");
Iterable<String> iterable2 = Arrays.asList("d", "e", "f", "a");
Set<String> test = Guavate.concatToSet(iterable1, iterable2);
assertEquals(test, ImmutableSet.of("a", "b", "c", "d", "e", "f"));
}

public void test_concatToSet_differentTypes() {
Iterable<Integer> iterable1 = Arrays.asList(1, 2, 3, 2);
Iterable<Double> iterable2 = Arrays.asList(10d, 20d, 30d);
Set<Number> test = Guavate.concatToSet(iterable1, iterable2);
assertEquals(test, ImmutableSet.of(1, 2, 3, 10d, 20d, 30d));
}

//-------------------------------------------------------------------------
public void test_combineMap() {
Map<String, String> map1 = ImmutableMap.of("a", "one", "b", "two");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import org.testng.annotations.Test;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.Guavate;
import com.opengamma.strata.collect.Messages;

Expand Down Expand Up @@ -164,29 +166,36 @@ public void test_withAdditionalFailures() {

//-------------------------------------------------------------------------
public void test_toValueWithFailures() {
List<Double> testList = ImmutableList.of(5d, 6d, 7d);
ValueWithFailures<Double> result = testList.stream()
ValueWithFailures<Double> result = Stream.of(5d, 6d, 7d)
.map(value -> mockCalc(value))
.collect(ValueWithFailures.toValueWithFailures(1d, (val1, val2) -> val1 * val2));

assertEquals(result.getValue(), 210d); //5 * 6 * 7 = 210

List<FailureItem> failures = result.getFailures();
assertEquals(failures.size(), 3); //One failure item for each element in testList.
assertEquals(failures.get(0).getMessage(), Messages.format("Error calculating result for input value {}", 5d));
assertEquals(failures.get(1).getMessage(), Messages.format("Error calculating result for input value {}", 6d));
assertEquals(failures.get(2).getMessage(), Messages.format("Error calculating result for input value {}", 7d));
}

public void test_toValueWithFailuresList() {
List<Double> testList = ImmutableList.of(5d, 6d, 7d);
ImmutableList<ValueWithFailures<Double>> listOfValueWithFailures = testList.stream()
public void test_toCombinedValuesAsList() {
ValueWithFailures<List<Double>> result = Stream.of(5d, 6d, 7d)
.map(value -> mockCalc(value))
.collect(toImmutableList());

ValueWithFailures<ImmutableList<Double>> result = listOfValueWithFailures.stream()
.collect(ValueWithFailures.toCombinedValuesAsList());
assertEquals(result.getValue(), ImmutableList.of(5d, 6d, 7d));

List<FailureItem> failures = result.getFailures();
assertEquals(failures.size(), 3); //One failure item for each element in testList.
assertEquals(failures.get(0).getMessage(), Messages.format("Error calculating result for input value {}", 5d));
assertEquals(failures.get(1).getMessage(), Messages.format("Error calculating result for input value {}", 6d));
assertEquals(failures.get(2).getMessage(), Messages.format("Error calculating result for input value {}", 7d));
}

assertEquals(result.getValue().size(), 3);
public void test_toCombinedValuesAsSet() {
ValueWithFailures<Set<Double>> result = Stream.of(5d, 6d, 7d)
.map(value -> mockCalc(value))
.collect(ValueWithFailures.toCombinedValuesAsSet());
assertEquals(result.getValue(), ImmutableSet.of(5d, 6d, 7d));

List<FailureItem> failures = result.getFailures();
assertEquals(failures.size(), 3); //One failure item for each element in testList.
Expand All @@ -196,14 +205,27 @@ public void test_toValueWithFailuresList() {
}

public void test_combineAsList() {
List<Double> testList = ImmutableList.of(5d, 6d, 7d);
ImmutableList<ValueWithFailures<Double>> listOfValueWithFailures = testList.stream()
ImmutableList<ValueWithFailures<Double>> listOfValueWithFailures = Stream.of(5d, 6d, 7d)
.map(value -> mockCalc(value))
.collect(toImmutableList());

ValueWithFailures<List<Double>> result = ValueWithFailures.combineValuesAsList(listOfValueWithFailures);
assertEquals(result.getValue(), ImmutableList.of(5d, 6d, 7d));

List<FailureItem> failures = result.getFailures();
assertEquals(failures.size(), 3); //One failure item for each element in testList.
assertEquals(failures.get(0).getMessage(), Messages.format("Error calculating result for input value {}", 5d));
assertEquals(failures.get(1).getMessage(), Messages.format("Error calculating result for input value {}", 6d));
assertEquals(failures.get(2).getMessage(), Messages.format("Error calculating result for input value {}", 7d));
}

public void test_combineAsSet() {
ImmutableList<ValueWithFailures<Double>> listOfValueWithFailures = Stream.of(5d, 6d, 7d)
.map(value -> mockCalc(value))
.collect(toImmutableList());

assertEquals(result.getValue().size(), 3);
ValueWithFailures<Set<Double>> result = ValueWithFailures.combineValuesAsSet(listOfValueWithFailures);
assertEquals(result.getValue(), ImmutableSet.of(5d, 6d, 7d));

List<FailureItem> failures = result.getFailures();
assertEquals(failures.size(), 3); //One failure item for each element in testList.
Expand Down