mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
classlib: add Collectors grouping by
This commit is contained in:
parent
c39efdc6d7
commit
697ad73762
|
@ -34,6 +34,7 @@ package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.teavm.classlib.java.io.TSerializable;
|
import org.teavm.classlib.java.io.TSerializable;
|
||||||
import org.teavm.classlib.java.lang.*;
|
import org.teavm.classlib.java.lang.*;
|
||||||
|
@ -668,6 +669,23 @@ public class THashMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
||||||
|
if (elementCount > 0) {
|
||||||
|
int prevModCount = modCount;
|
||||||
|
for (int i = 0; i < elementData.length; i++) {
|
||||||
|
HashEntry<K, V> entry = elementData[i];
|
||||||
|
while (entry != null) {
|
||||||
|
entry.value = function.apply(entry.key, entry.value);
|
||||||
|
entry = entry.next;
|
||||||
|
if (prevModCount != modCount) {
|
||||||
|
throw new TConcurrentModificationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int computeHashCode(Object key) {
|
static int computeHashCode(Object key) {
|
||||||
return key.hashCode();
|
return key.hashCode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,14 @@ public interface TMap<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
||||||
|
TIterator<Entry<K, V>> iterator = entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
TMap.Entry<K, V> next = iterator.next();
|
||||||
|
next.setValue(function.apply(next.getKey(), next.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static <K, V> TMap<K, V> of() {
|
static <K, V> TMap<K, V> of() {
|
||||||
return TCollections.emptyMap();
|
return TCollections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,55 @@ public final class TCollectors {
|
||||||
TCollector.Characteristics.IDENTITY_FINISH);
|
TCollector.Characteristics.IDENTITY_FINISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <E, K> TCollector<E, ?, Map<K, List<E>>> groupingBy(Function<? super E, ? extends K> keyExtractor) {
|
||||||
|
return groupingBy(keyExtractor, toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E, K, V, I> TCollector<E, ?, Map<K, V>> groupingBy(
|
||||||
|
Function<? super E, ? extends K> keyExtractor,
|
||||||
|
TCollector<? super E, I, V> downstream) {
|
||||||
|
return groupingBy(keyExtractor, HashMap::new, downstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E, K, V, I, M extends Map<K, V>> TCollector<E, ?, M> groupingBy(
|
||||||
|
Function<? super E, ? extends K> keyExtractor,
|
||||||
|
Supplier<M> mapFactory,
|
||||||
|
TCollector<? super E, I, V> downstream) {
|
||||||
|
BiConsumer<Map<K, I>, E> mapAppender = (m, t) -> {
|
||||||
|
K key = keyExtractor.apply(t);
|
||||||
|
I container = m.computeIfAbsent(key, k -> downstream.supplier().get());
|
||||||
|
downstream.accumulator().accept(container, t);
|
||||||
|
};
|
||||||
|
BinaryOperator<Map<K, I>> mapMerger = (m1, m2) -> {
|
||||||
|
for (Map.Entry<K, I> e : m2.entrySet()) {
|
||||||
|
m1.merge(e.getKey(), e.getValue(), downstream.combiner());
|
||||||
|
}
|
||||||
|
return m1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (downstream.characteristics().contains(TCollector.Characteristics.IDENTITY_FINISH)) {
|
||||||
|
return TCollector.of(castFactory(mapFactory), mapAppender, mapMerger,
|
||||||
|
castFunction(Function.identity()), TCollector.Characteristics.IDENTITY_FINISH);
|
||||||
|
} else {
|
||||||
|
Function<I, I> replacer = castFunction(downstream.finisher());
|
||||||
|
Function<Map<K, I>, M> finisher = toReplace -> {
|
||||||
|
toReplace.replaceAll((k, v) -> replacer.apply(v));
|
||||||
|
return (M) toReplace;
|
||||||
|
};
|
||||||
|
return TCollector.of(castFactory(mapFactory), mapAppender, mapMerger, finisher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <A, C> Supplier<A> castFactory(Supplier<C> supp) {
|
||||||
|
return (Supplier<A>) supp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <A, B, C, D> Function<A, B> castFunction(Function<C, D> func) {
|
||||||
|
return (Function<A, B>) func;
|
||||||
|
}
|
||||||
|
|
||||||
public static <T, A, R, K> TCollector<T, A, K> collectingAndThen(
|
public static <T, A, R, K> TCollector<T, A, K> collectingAndThen(
|
||||||
TCollector<T, A, R> downstream,
|
TCollector<T, A, R> downstream,
|
||||||
Function<R, K> finisher) {
|
Function<R, K> finisher) {
|
||||||
|
|
|
@ -20,7 +20,9 @@ import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.teavm.junit.TeaVMTestRunner;
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
|
@ -122,4 +124,15 @@ public class MapTest {
|
||||||
assertNull("Iterator did not return all of expected elements", e);
|
assertNull("Iterator did not return all of expected elements", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReplaceAll() {
|
||||||
|
Map<String, Integer> base = Map.of("a", 1, "b", 2);
|
||||||
|
Map<String, Integer> hashMap = new HashMap<>(base);
|
||||||
|
Map<String, Integer> treeMap = new TreeMap<>(base);
|
||||||
|
hashMap.replaceAll((k, v) -> v * 10);
|
||||||
|
treeMap.replaceAll((k, v) -> v * 10);
|
||||||
|
assertEquals(Map.of("a", 10, "b", 20), hashMap);
|
||||||
|
assertEquals(Map.of("a", 10, "b", 20), treeMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,4 +78,16 @@ public class CollectorsTest {
|
||||||
assertEquals(expected,
|
assertEquals(expected,
|
||||||
IntStream.range(1, 4).boxed().collect(Collectors.toMap(Function.identity(), Function.identity())));
|
IntStream.range(1, 4).boxed().collect(Collectors.toMap(Function.identity(), Function.identity())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void groupingBy() {
|
||||||
|
List<Integer> numbers = List.of(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
|
||||||
|
assertEquals(Map.of(1, List.of(1), 2, List.of(2, 2),
|
||||||
|
3, List.of(3, 3, 3), 4, List.of(4, 4, 4, 4)),
|
||||||
|
numbers.stream().collect(Collectors.groupingBy(Function.identity())));
|
||||||
|
assertEquals(Map.of(1, 1, 2, 4, 3, 9, 4, 16),
|
||||||
|
numbers.stream().collect(Collectors.groupingBy(Function.identity(),
|
||||||
|
Collectors.collectingAndThen(Collectors.toList(),
|
||||||
|
l -> l.stream().mapToInt(i -> i).sum()))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user