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

io.activej.common.collection.CollectionUtils Maven / Gradle / Ivy

There is a newer version: 4.3-r8
Show newest version
/*
 * Copyright (C) 2020 ActiveJ LLC.
 *
 * 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 io.activej.common.collection;

import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;

public class CollectionUtils {

	public static  List concat(Collection list1, Collection list2) {
		List result = new ArrayList<>(list1.size() + list2.size());
		result.addAll(list1);
		result.addAll(list2);
		return result;
	}

	@SafeVarargs
	public static  Set set(T... items) {
		return new LinkedHashSet<>(asList(items));
	}

	public static  Set difference(Set a, Set b) {
		return a.stream().filter(t -> !b.contains(t)).collect(toSet());
	}

	public static  Set intersection(Set a, Set b) {
		return a.size() < b.size() ?
				a.stream().filter(b::contains).collect(toSet()) :
				b.stream().filter(a::contains).collect(toSet());
	}

	public static  boolean hasIntersection(Set a, Set b) {
		return a.size() < b.size() ?
				a.stream().anyMatch(b::contains) :
				b.stream().anyMatch(a::contains);
	}

	public static  Set union(Set a, Set b) {
		return Stream.concat(a.stream(), b.stream()).collect(toSet());
	}

	public static  Set union(List> sets) {
		return sets.stream().flatMap(Collection::stream).collect(toSet());
	}

	@SafeVarargs
	public static  Set union(Set... sets) {
		return union(asList(sets));
	}

	public static  T first(Iterable iterable) {
		return iterable.iterator().next();
	}

	public static  List list() {
		return emptyList();
	}

	@SuppressWarnings("unchecked")
	public static  List list(T... items) {
		return asList(items);
	}

	public static  Stream iterate(Supplier supplier, Predicate hasNext) {
		return iterate(supplier.get(), hasNext, $ -> supplier.get());
	}

	public static  Stream iterate(T seed, Predicate hasNext, UnaryOperator f) {
		requireNonNull(f);
		return iterate(
				new Iterator() {
					T item = seed;

					@Override
					public boolean hasNext() {
						return hasNext.test(item);
					}

					@Override
					public T next() {
						T next = item;
						item = f.apply(item);
						return next;
					}
				});
	}

	public static  Stream iterate(Iterator iterator) {
		return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator,
				Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
	}

	public static  String toLimitedString(Collection collection, int limit) {
		return collection.stream()
				.limit(limit)
				.map(element -> element == collection ? "(this Collection)" : element.toString())
				.collect(joining(",", "[", collection.size() <= limit ? "]" : ", ..and " + (collection.size() - limit) + " more]"));
	}

	public static  String toLimitedString(Map map, int limit) {
		return map.entrySet().stream()
				.limit(limit)
				.map(element -> {
					K key = element.getKey();
					V value = element.getValue();
					String keyString = key == map ? "(this Map)" : key.toString();
					String valueString = value == map ? "(this Map)" : value.toString();
					return keyString + '=' + valueString;
				})
				.collect(joining(",", "{", map.size() <= limit ? "}" : ", ..and " + (map.size() - limit) + " more}"));
	}

	private static final Iterator EMPTY_ITERATOR = new Iterator() {
		@Override
		public boolean hasNext() {
			return false;
		}

		@Override
		public Object next() {
			throw new NoSuchElementException();
		}
	};

	@SuppressWarnings("unchecked")
	public static  Iterator emptyIterator() {
		return (Iterator) EMPTY_ITERATOR;
	}

	public static  Iterator asIterator(T item) {
		return new Iterator() {
			boolean hasNext = true;

			@Override
			public boolean hasNext() {
				return hasNext;
			}

			@Override
			public T next() {
				if (!hasNext()) throw new NoSuchElementException();
				hasNext = false;
				return item;
			}
		};
	}

	public static  Iterator asIterator(T item1, T item2) {
		return new Iterator() {
			int i = 0;

			@Override
			public boolean hasNext() {
				return i < 2;
			}

			@Override
			public T next() {
				if (!hasNext()) throw new NoSuchElementException();
				return i++ == 0 ? item1 : item2;
			}
		};
	}

	@SafeVarargs
	public static  Iterator asIterator(T... items) {
		return new Iterator() {
			int i = 0;

			@Override
			public boolean hasNext() {
				return i < items.length;
			}

			@Override
			public T next() {
				if (!hasNext()) throw new NoSuchElementException();
				return items[i++];
			}
		};
	}

	@SafeVarargs
	public static  Iterator asIterator(T head, T... tail) {
		return new Iterator() {
			int i = 0;

			@Override
			public boolean hasNext() {
				return i <= tail.length;
			}

			@Override
			public T next() {
				if (!hasNext()) throw new NoSuchElementException();
				return i == 0 ? head : tail[i++ - 1];
			}
		};
	}

	public static  Iterator transformIterator(Iterator iterator, Function fn) {
		return new Iterator() {
			@Override
			public boolean hasNext() {
				return iterator.hasNext();
			}

			@Override
			public R next() {
				return fn.apply(iterator.next());
			}
		};
	}

	public static  Iterator concat(Iterator iterator1, Iterator iterator2) {
		return concatIterators(asIterator(iterator1, iterator2));
	}

	public static  Iterator append(Iterator iterator, T value) {
		return concatIterators(asIterator(iterator, asIterator(value)));
	}

	public static  Iterator prepend(T value, Iterator iterator) {
		return concatIterators(asIterator(asIterator(value), iterator));
	}

	public static  Iterator concatIterators(Iterator> iterators) {
		return new Iterator() {
			@Nullable Iterator it = iterators.hasNext() ? iterators.next() : null;

			@Override
			public boolean hasNext() {
				return it != null;
			}

			@Override
			public T next() {
				if (it == null) throw new NoSuchElementException();
				T next = it.next();
				if (!it.hasNext()) {
					it = iterators.hasNext() ? iterators.next() : null;
				}
				return next;
			}
		};
	}

	public static  Map keysToMap(Set keys, Function fn) {
		return keysToMap(keys.stream(), fn);
	}

	public static  Map keysToMap(Stream stream, Function fn) {
		LinkedHashMap result = new LinkedHashMap<>();
		stream.forEach(key -> result.put(key, fn.apply(key)));
		return result;
	}

	public static  Map entriesToMap(Stream> stream) {
		LinkedHashMap result = new LinkedHashMap<>();
		stream.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
		return result;
	}

	public static  Map transformMapValues(Map map, Function function) {
		LinkedHashMap result = new LinkedHashMap<>(map.size());
		map.forEach((key, value) -> result.put(key, function.apply(value)));
		return result;
	}

	public static  Map map() {
		return new LinkedHashMap<>();
	}

	public static  Map map(K key1, V value1) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		map.put(key2, value2);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		map.put(key2, value2);
		map.put(key3, value3);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		map.put(key2, value2);
		map.put(key3, value3);
		map.put(key4, value4);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4, K key5, V value5) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		map.put(key2, value2);
		map.put(key3, value3);
		map.put(key4, value4);
		map.put(key5, value5);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4, K key5, V value5, K key6, V value6) {
		Map map = new LinkedHashMap<>();
		map.put(key1, value1);
		map.put(key2, value2);
		map.put(key3, value3);
		map.put(key4, value4);
		map.put(key5, value5);
		map.put(key6, value6);
		return map;
	}

	public static  T getLast(Iterable iterable) {
		Iterator iterator = iterable.iterator();
		while (iterator.hasNext()) {
			T next = iterator.next();
			if (!iterator.hasNext()) {
				return next;
			}
		}
		throw new IllegalArgumentException("Empty iterable");
	}

	public static  T getFirst(Iterable iterable) {
		Iterator iterator = iterable.iterator();
		if (iterator.hasNext()) {
			return iterator.next();
		}
		throw new IllegalArgumentException("Empty iterable");
	}

	public static boolean isBijection(Map map) {
		return new HashSet<>(map.values()).size() == map.size();
	}
}