/* * Apache License * Version 2.0, January 2004 * http://www.apache.org/licenses/ * * Copyright 2013 Aurelian Tutuianu * Copyright 2014 Aurelian Tutuianu * Copyright 2015 Aurelian Tutuianu * Copyright 2016 Aurelian Tutuianu * * 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 rapaio.util.stream; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collectors; import static java.util.stream.Collectors.mapping; import static java.util.stream.Collectors.toList; /** * Various useful stream collectors. * <p> * Created by <a href="mailto:padreati@yahoo.com">Aurelian Tutuianu</a> on 3/19/15. */ @Deprecated public class SCollectors { public static <K> Collector<K, ?, NavigableMap<Long, List<K>>> countingTop() { return countingTop(k -> k); } public static <K, M> Collector<K, ?, NavigableMap<Long, M>> countingTop(Collector<K, ?, M> downstream) { return countingTop(k -> k, downstream); } public static <K, T> Collector<T, ?, NavigableMap<Long, List<K>>> countingTop(Function<T, K> classifier) { return countingTop(classifier, toList()); } /** * Builds a group by counting in reverse order. * * @param classifier maps input type to the key used for grouping * @param <T> class of the original type * @param <K> class of the key type * @return a navigable map in reverse order */ public static <T, K, M> Collector<T, ?, NavigableMap<Long, M>> countingTop(Function<T, K> classifier, Collector<K, ?, M> downstream) { return new Collector<T, Map<K, Long>, NavigableMap<Long, M>>() { @Override public Supplier<Map<K, Long>> supplier() { return HashMap::new; } @Override public BiConsumer<Map<K, Long>, T> accumulator() { return (acc, obj) -> { K k = classifier.apply(obj); Long counter = acc.get(k); if (counter != null) { acc.put(k, acc.get(k) + 1); } else { acc.put(k, 1L); } }; } @Override public BinaryOperator<Map<K, Long>> combiner() { return (left, right) -> { right.entrySet() .forEach(e -> left.put(e.getKey(), left.containsKey(e.getKey()) ? left.get(e.getKey()) + e.getValue() : e.getValue())); return left; }; } @Override public Function<Map<K, Long>, NavigableMap<Long, M>> finisher() { return m1 -> m1.entrySet().stream() .collect(Collectors.groupingBy(Map.Entry::getValue, TreeMap::new, mapping(Map.Entry::getKey, downstream))) .descendingMap(); } @Override public Set<Characteristics> characteristics() { return EnumSet.noneOf(Characteristics.class); } }; } public static <T> Collector<T, List<List<T>>, List<List<T>>> slidingCollector(int size, int step) { final int window = Math.max(size, step); return new Collector<T, List<List<T>>, List<List<T>>>() { private final Queue<T> buffer = new ArrayDeque<>(); private int totalIn = 0; @Override public Supplier<List<List<T>>> supplier() { return ArrayList::new; } @Override public BiConsumer<List<List<T>>, T> accumulator() { return (lists, t) -> { buffer.offer(t); ++totalIn; if (buffer.size() == window) { dumpCurrent(lists); shiftBy(step); } }; } @Override public Function<List<List<T>>, List<List<T>>> finisher() { return lists -> { if (!buffer.isEmpty()) { final int totalOut = estimateTotalOut(); if (totalOut > lists.size()) { dumpCurrent(lists); } } return lists; }; } private int estimateTotalOut() { return Math.max(0, (totalIn + step - size - 1) / step) + 1; } private void dumpCurrent(List<List<T>> lists) { final List<T> batch = buffer.stream().limit(size).collect(Collectors.toList()); lists.add(batch); } private void shiftBy(int by) { for (int i = 0; i < by; i++) { buffer.remove(); } } @Override public BinaryOperator<List<List<T>>> combiner() { return (l1, l2) -> { throw new UnsupportedOperationException("Combining not possible"); }; } @Override public Set<Characteristics> characteristics() { return EnumSet.noneOf(Characteristics.class); } }; } }