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

com.jongsoft.lang.collection.support.Collections Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License
 *
 * Copyright 2016-2019 Jong Soft.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.jongsoft.lang.collection.support;

import java.util.ArrayList;
import java.util.Objects;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collector;

import com.jongsoft.lang.API;
import com.jongsoft.lang.Control;
import com.jongsoft.lang.collection.*;
import com.jongsoft.lang.collection.tuple.Pair;
import com.jongsoft.lang.control.Optional;

public final class Collections {

    private Collections() {
        // hidden constructor utility class
    }

    public static  Map> groupBy(Supplier> instanceSupplier, List source,
                                                                    Function keyGenerator) {
        Objects.requireNonNull(keyGenerator, "keyGenerator is null");
        Map> result = com.jongsoft.lang.Collections.Map();
        for (U element : source) {
            K key = keyGenerator.apply(element);
            List elementsForKey = Control.Option(result.get(key))
                                            .getOrSupply(instanceSupplier);

            result = result.put(key, elementsForKey.append(element));
        }

        return result;
    }

    public static > Collector, K> collector(Function, K> finisher) {
        final BinaryOperator> combiner = (left, right) -> {
            left.addAll(right);
            return left;
        };

        return Collector.of(ArrayList::new, ArrayList::add, combiner, finisher::apply);
    }

    public static  Pair neumaierSum(Traversable traversable, ToDoubleFunction toDoubleFunction) {
        int count = 0;
        double sum = 0.0;
        double compensation = 0.0;

        for (T t : traversable) {
            double value = toDoubleFunction.applyAsDouble(t);
            double y = sum + value;

            if (Math.abs(sum) >= Math.abs(value)) {
                compensation += (sum - y) + value;
            } else {
                compensation += (value - y) + sum;
            }

            sum = y;
            count++;
        }

        sum += compensation;
        return API.Tuple(count, sum);
    }

    public static  double median(Traversable traversable, ToDoubleFunction toDoubleFunction) {
        for (T element : traversable) {
            toDoubleFunction.applyAsDouble(element);
        }

        if (traversable instanceof List) {
            var casted = (List) traversable;
            var elCount = casted.size();
            if (elCount % 2 == 0) {
                return (toDoubleFunction.applyAsDouble(casted.get(elCount / 2))
                        + toDoubleFunction.applyAsDouble(casted.get(elCount / 2 - 1))) / 2;
            } else {
                return toDoubleFunction.applyAsDouble(casted.get(elCount / 2));
            }
        }

        return 0;
    }

    @SuppressWarnings("unchecked")
    public static  Optional compareGreatestSmallest(Traversable traversable, boolean maximum) {
        Comparable value = null;
        for (T element : traversable) {
            if (!(element instanceof Comparable)) {
                throw new ClassCastException("Element must be of type comparable to be able to determine max or min value.");
            }

            if (value == null
                    || (maximum && value.compareTo(element) < 0)
                    || (!maximum && value.compareTo(element) > 0)) {
                value = (Comparable) element;
            }
        }

        return Control.Option((T) value);
    }

    @SuppressWarnings("unchecked")
    public static > K filter(K seed, Iterable source, Predicate filter) {
        K result = seed;

        for (T element : source) {
            if (filter.test(element)) {
                result = (K) result.append(element);
            }
        }

        return result;
    }

    public static  String textValueOf(String type, Collection collection) {
        StringBuilder text = new StringBuilder(type);

        text.append("[");
        if (collection != null) {
            int index = 0;
            for (T element : collection) {
                text.append(element);

                index++;
                if (index < collection.size()) {
                    text.append(", ");
                }
            }
        }
        text.append("]");

        return text.toString();
    }

}