classlib: add Collectors.reducing (#704)

This commit is contained in:
Ivan Hetman 2023-06-06 12:08:15 +03:00 committed by GitHub
parent 7104edb592
commit d209a5f02e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 0 deletions

View File

@ -749,4 +749,21 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
}
return sb.toString();
}
public String repeat(int count) {
if (count < 0) {
throw new IllegalArgumentException();
}
if (count == 1) {
return this.toString();
}
if (characters.length == 0 || count == 0) {
return "";
}
TStringBuilder builder = new TStringBuilder(characters.length * count);
for (int i = 0; i < count; i++) {
builder.append(this.toString());
}
return builder.toString();
}
}

View File

@ -18,11 +18,13 @@ package org.teavm.classlib.java.util.stream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
@ -187,4 +189,68 @@ public final class TCollectors {
newCharacteristics);
}
private static class Reducer<T> {
private final BinaryOperator<T> op;
private boolean present;
private T value;
private Reducer(BinaryOperator<T> op) {
this.op = op;
}
private Reducer(BinaryOperator<T> op, T value) {
this.op = op;
consume(value);
}
private void consume(T t) {
if (present) {
value = op.apply(value, t);
} else {
value = t;
present = true;
}
}
private Reducer<T> merge(Reducer<T> other) {
if (other.present) {
consume(other.value);
}
return this;
}
private Optional<T> getOpt() {
return present ? Optional.of(value) : Optional.empty();
}
private T get() {
return value;
}
}
public static <T> TCollector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {
return TCollector.of(() -> new Reducer<>(op), Reducer::consume, Reducer::merge, Reducer::getOpt);
}
public static <T> TCollector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {
return TCollector.of(() -> new Reducer<>(op, identity), Reducer::consume, Reducer::merge, Reducer::get);
}
public static <T, U> TCollector<T, ?, U> reducing(U identity,
Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {
return TCollector.of(() -> new Reducer<>(op, identity),
(red, t) -> red.consume(mapper.apply(t)), Reducer::merge, Reducer::get);
}
public static <T> TCollector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) {
return reducing(BinaryOperator.minBy(comparator));
}
public static <T> TCollector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) {
return reducing(BinaryOperator.maxBy(comparator));
}
public static <T> TCollector<T, ?, Long> counting() {
return reducing(0L, e -> 1L, Long::sum);
}
}

View File

@ -18,10 +18,12 @@ package org.teavm.classlib.java.util.stream;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@ -90,4 +92,26 @@ public class CollectorsTest {
Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream().mapToInt(i -> i).sum()))));
}
@Test
public void reducing() {
assertEquals(Optional.of("abc"), Stream.of("a", "b", "c")
.collect(Collectors.reducing(String::concat)));
assertEquals(Optional.empty(), Stream.<String>empty()
.collect(Collectors.reducing(String::concat)));
assertEquals("abc", Stream.of("a", "b", "c")
.collect(Collectors.reducing("", String::concat)));
assertEquals("aabbcc", Stream.of("a", "b", "c")
.collect(Collectors.reducing("", s -> s.repeat(2), String::concat)));
}
@Test
public void minMax() {
assertEquals(Optional.of("a"), Stream.of("a", "bb", "ccc")
.collect(Collectors.minBy(Comparator.comparing(String::length))));
assertEquals(Optional.of("ccc"), Stream.of("a", "bb", "ccc")
.collect(Collectors.maxBy(Comparator.naturalOrder())));
assertEquals(Optional.empty(), Stream.<String>empty()
.collect(Collectors.minBy(Comparator.naturalOrder())));
}
}