Java tutorial
/* * Copyright 2011-2016 B2i Healthcare Pte Ltd, http://b2i.sg * * 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 com.b2international.commons.collect; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static com.google.common.collect.Sets.newHashSetWithExpectedSize; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import com.b2international.collections.PrimitiveSets; import com.b2international.collections.longs.AbstractLongIterator; import com.b2international.collections.longs.LongCollection; import com.b2international.collections.longs.LongCollections; import com.b2international.collections.longs.LongIterator; import com.b2international.collections.longs.LongSet; import com.b2international.commons.CompareUtils; import com.b2international.commons.StopWatch; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.primitives.Longs; /** * Utility class for {@link LongSet}s. */ public class LongSets { /** * Returns with the difference of two sets. The * returned set contains all elements that are contained by {@code set1} and * not contained by {@code set2}. {@code set2} may also contain elements not * present in {@code set1}; these are simply ignored. The iteration order of * the returned set matches that of {@code set1}. * @param set1 Cannot be {@code null}. * @param set2 Cannot be {@code null}. * @return a view of the difference of the two sets. */ public static LongSet difference(final LongSet set1, final LongSet set2) { checkNotNull(set1, "The set1 argument cannot be null."); checkNotNull(set2, "The set2 argument cannot be null."); if (CompareUtils.isEmpty(set1)) { //nothing to do return LongCollections.emptySet(); } final LongSet result = PrimitiveSets.newLongOpenHashSet(set1); result.removeAll(set2); return result; } /** * Returns with the intersection of two sets. The * returned set contains all elements that are contained by both backing sets. * The iteration order of the returned set matches that of {@code set1}. * * <p><b>Note:</b> The returned view performs slightly better when {@code * set1} is the smaller of the two sets. If you have reason to believe one of * your sets will generally be smaller than the other, pass it first. * * @param set1 Cannot be {@code null}. * @param set2 Cannot be {@code null}. * @return a view of the intersection of the two sets. */ public static LongSet intersection(final LongSet set1, final LongSet set2) { checkNotNull(set1, "The set1 argument cannot be null."); checkNotNull(set2, "The set2 argument cannot be null."); if (CompareUtils.isEmpty(set1)) { //nothing to do return LongCollections.emptySet(); } final LongSet result = PrimitiveSets.newLongOpenHashSet(set1); result.retainAll(set2); return result; } /** * Returns the number of elements remaining in {@link LongIterator iterator}. * The iterator will be left exhausted: its {@link LongIterator#hasNext()} method will return {@code false}. * @param itr the iterator. * @return the number of remaining elements. */ private static int size(final LongIterator itr) { checkNotNull(itr, "Long iterator argument cannot be null."); int $ = 0; while (itr.hasNext()) { itr.next(); $++; } return $; } /** * Returns with an array containing all long values as a string. * @param collection the collection of primitive longs. * @return an array of strings. */ public static String[] toStringArray(final LongCollection collection) { checkNotNull(collection, "Long collection argument cannot be null."); final String[] ids = new String[collection.size()]; int i = 0; for (final LongIterator iterator = collection.iterator(); iterator.hasNext(); /*nothing*/) { ids[i++] = Long.toString(iterator.next()); } return ids; } /** * Returns with a list containing all long values. * @param collection the collection of primitive longs * @return a list of long values. */ public static List<Long> toList(final LongCollection collection) { checkNotNull(collection, "Long collection argument cannot be null."); collection.trimToSize(); return Longs.asList(collection.toArray()); } /** * Returns with a set containing all long values. * @param collection the collection of primitive longs * @return a set of long values. */ public static Set<Long> toSet(final LongCollection collection) { checkNotNull(collection, "Long collection argument cannot be null."); collection.trimToSize(); final Set<Long> $ = newHashSetWithExpectedSize(collection.size()); for (final LongIterator itr = collection.iterator(); itr.hasNext(); /* */) { $.add(itr.next()); } return $; } /** * Returns with an {@link List} containing all long values as a string. * @param collection the collection of primitive longs. * @return an list of strings. */ public static List<String> toStringList(final LongCollection collection) { checkNotNull(collection, "Long collection argument cannot be null."); return Lists.newArrayList(toStringArray(collection)); } /** * Returns with an {@link Set} containing all long values as a string. * @param collection the collection of primitive longs. * @return a set of strings. */ public static Set<String> toStringSet(final LongCollection collection) { checkNotNull(collection, "Long collection argument cannot be null."); return newHashSet(toStringArray(collection)); } /** * Creates and returns with a new mutable {@link LongOpenHashSet} instance containing the * elements in indeterministic order. * @param itr the elements that the new set instance should contain. * @return the new set instance containing each element of the iterator without duplicates. */ public static LongSet newLongSet(final LongIterator itr) { final LongSet $ = PrimitiveSets.newLongOpenHashSet(); while (itr.hasNext()) { $.add(itr.next()); } return $; } /** * Evaluates the procedure argument on each element of the given iterator. * @param iterator the iterator which elements will be evaluated against the procedure. * @param procedure the procedure to apply on each element of the given iterator of primitive long numbers. */ public static void forEach(final LongIterator itr, final LongCollectionProcedure procedure) { checkNotNull(procedure, "procedure"); while (itr.hasNext()) { procedure.apply(itr.next()); } } /** * Evaluates the procedure argument on each element of the given collection. * @param collection the collection which each element will be evaluated against the procedure. * @param procedure the procedure to apply on each element of the given collection of primitive long elements. */ public static void forEach(final LongCollection collection, final LongCollectionProcedure procedure) { forEach(collection.iterator(), procedure); } /** * Just as {@link #forEach(LongIterator, LongCollectionProcedure)} but parallel evaluates the procedure argument * on each element of the given iterator. * @param iterator the iterator which elements will be evaluated against the procedure. * @param procedure the procedure to apply on each element of the given iterator of primitive long numbers. */ public static void parallelForEach(final LongIterator iterator, final LongCollectionProcedure procedure) { checkNotNull(procedure, "procedure"); final LongListIteratorWrapper itr = new LongListIteratorWrapper(iterator); final int nThreads = Runtime.getRuntime().availableProcessors(); final AtomicReference<ExecutorService> service = new AtomicReference<ExecutorService>(); try { service.set(Executors.newFixedThreadPool(nThreads)); @SuppressWarnings("unchecked") final Future<Void>[] $ = new Future[size(itr)]; itr.reset(); final AtomicInteger i = new AtomicInteger(); forEach(itr, new LongCollectionProcedure() { @Override public void apply(final long input) { $[i.getAndIncrement()] = service.get().submit(new Callable<Void>() { @Override public Void call() throws Exception { procedure.apply(input); return com.b2international.commons.Void.VOID; } }); } }); if (null != service && null != service.get()) { service.get().shutdown(); service.set(null); } for (final Future<Void> f : $) { f.get(); } } catch (final InterruptedException e) { Thread.interrupted(); throw new RuntimeException(e); } catch (final ExecutionException e) { throw new RuntimeException(e); } finally { if (null != service && null != service.get()) { service.get().shutdown(); service.set(null); } } } /** * Just as {@link #forEach(LongCollection, LongCollectionProcedure)} but parallel evaluates the procedure argument * on each element of the given collection. * @param collection the collection which each element will be evaluated against the procedure. * @param procedure the procedure to apply on each element of the given iterator of primitive long numbers. */ public static void parallelForEach(final LongCollection collection, final LongCollectionProcedure procedure) { parallelForEach(collection.iterator(), procedure); } /** * Returns with an iterator instance that applies the {@code function} to each element of the * given {@code from} iterable. * @param from the iterable to transform each element. * @param function the function that is evaluated for each element of the {@code from} iterable. * @return an the iterator. */ public static <F> LongIterator transform(final Iterable<F> from, final LongFunction<? super F> function) { checkNotNull(from, "Iterable argument cannot be null."); checkNotNull(function, "Function argument cannot be null."); return new AbstractLongIterator() { private final Iterator<F> delegate = from.iterator(); private final LongFunction<? super F> _function = function; @Override protected long computeNext() { while (delegate.hasNext()) { return _function.apply(delegate.next()); } return endOfData(); } }; } /** * Transforms the given {@link LongCollection} into a collection of object based on the {@link InverseLongFunction function} argument. * @param fromCollection the collection of primitive long values to transform. * @param function the function for the transformation. * @return the transformed collection of long values. */ public static <T> Collection<T> transform(final LongCollection fromCollection, final InverseLongFunction<? extends T> function) { checkNotNull(fromCollection, "fromCollection"); checkNotNull(function, "function"); @SuppressWarnings("unchecked") final Collection<T> toCollection = (Collection<T>) (fromCollection instanceof LongSet ? newHashSet() : newArrayList()); for (final LongIterator itr = fromCollection.iterator(); itr.hasNext(); /**/) { toCollection.add(function.apply(itr.next())); } return toCollection; } /** * Combines the {@link LongIterator iterator} of the given collections into a single one. * @param collection the first collection. * @param others the other ones. * @return the combined iterator. */ public static LongIterator iterator(final LongCollection collection, final LongCollection... others) { return concat(Iterables.transform(Lists.asList(checkNotNull(collection, "collection"), others), new Function<LongCollection, LongIterator>() { @Override public LongIterator apply(final LongCollection longCollection) { return longCollection.iterator(); } }).iterator()); } /** * Concatenates the given long iterators into a single iterators. * @param itr the first iterator. * @param others the other ones. * @return the concatenated iterators. */ public static LongIterator concat(final LongIterator itr, final LongIterator... others) { return concat(Lists.asList(checkNotNull(itr, "itr"), others).iterator()); } /** * Concatenates the given {@link LongIterator iterators} into a single iterators. * @param iterators the iterators to combine. * @return the concatenated iterators. */ public static LongIterator concat(final Iterator<LongIterator> iterators) { return new LongIterator() { private LongIterator current = LongCollections.emptyIterator(); private LongIterator removeFrom; @Override public void remove() { checkState(removeFrom != null); removeFrom.remove(); removeFrom = null; } @Override public long next() { if (!hasNext()) { throw new NoSuchElementException(); } removeFrom = current; return current.next(); } @Override public boolean hasNext() { boolean currentHasNext; while (!(currentHasNext = checkNotNull(current).hasNext()) && iterators.hasNext()) { current = iterators.next(); } return currentHasNext; } }; } /** * Returns the elements of {@code unfiltered} that satisfy the given {@link LongPredicate predicate}. * @param unfiltered the set to filter. * @param predicate the predicate. * @return a modifiable filtered collection based on the {@code unfiltered} one. */ public static LongSet filter(final LongSet unfiltered, final LongPredicate predicate) { checkNotNull(unfiltered, "unfiltered"); checkNotNull(predicate, "predicate"); final LongSet copy = PrimitiveSets.newLongOpenHashSet(unfiltered); for (final LongIterator itr = copy.iterator(); itr.hasNext(); /* */) { final long value = itr.next(); if (!predicate.apply(value)) { itr.remove(); } } return copy; } private LongSets() { /*suppress instantiation*/ } /** * Procedure acting as a {@link LongFunction function} and providing no return value. */ public static interface LongCollectionProcedure { /** * Applies the current function to the primitive long {@code input}. * @param input the input primitive long to apply on the current procedure. */ void apply(final long input); } /** * Transformation from an object to a primitive long value. * * @param <F> type of the function input * @see InverseLongFunction */ public static interface LongFunction<F> { /** * Applies the current function to the object of type {@code F} and returns with * a primitive long value. * @param input the input object to transform into a primitive long value. * @return the transformed value. */ long apply(final F input); } /** * Transformation from a primitive long value into an object. * * @param <T> type of the function output * @see LongFunction */ public static interface InverseLongFunction<T> { /** * Applies the current function to the primitive long value and returns with * an object of type {@code T} * @param input the primitive long value to transform into an object. * @return the transformed value. */ T apply(final long input); } /** * Determines a {@code true} or {@code false} value for a given primitive long input. */ public static interface LongPredicate { /** * Returns the result of applying this predicate to {@code input} primitive long. */ boolean apply(final long input); /**Predicate always producing {@code true} result.*/ public static final LongPredicate ALL_PREDICATE = new LongPredicate() { @Override public boolean apply(final long input) { return true; } }; } /** * Predicate that evaluates to {@code true} if the primitive long being tested is a member of * any of the underlying collections. * */ /*default*/ static final class InLongPredicate implements LongPredicate { private final Iterable<? extends LongCollection> collections; /*default*/ InLongPredicate(final Iterable<? extends LongCollection> collections) { this.collections = checkNotNull(collections, "collections"); } @Override public boolean apply(final long input) { for (final LongCollection collection : collections) { if (collection.contains(input)) { return true; } } return false; } } /** * Predicates that negates evaluation of the delegate predicate. * */ /*default*/ static final class NotLongPredicate implements LongPredicate { private final LongPredicate predicate; /*default*/ NotLongPredicate(final LongPredicate predicate) { this.predicate = checkNotNull(predicate, "predicate"); } @Override public boolean apply(final long input) { return !predicate.apply(input); } } /** * Creates and returns with a new {@link LongPredicate} instance that evaluates to {@code true} if the primitive * long being tested is a member of any of the underlying long collections. * @param collections the collections to check against the membership. * @return the predicate. */ public static LongPredicate in(final Iterable<? extends LongCollection> collections) { return new InLongPredicate(checkNotNull(collections, "collections")); } /** * Creates and returns with a new {@link LongPredicate} instance that evaluates to {@code true} if the primitive * long being tested is a member of any of the underlying long collections. * @param collection the collection. * @param others the others. * @return the predicate. */ public static LongPredicate in(final LongCollection collection, final LongCollection... others) { return new InLongPredicate( Lists.asList(checkNotNull(collection, "collection"), checkNotNull(others, "others"))); } /** * Creates a new predicate instance that always negates the argument one. * @param predicate the predicate to negate. * @return a new NOT predicate. */ public static LongPredicate not(final LongPredicate predicate) { return new NotLongPredicate(checkNotNull(predicate, "predicate")); } public static void main(final String[] args) { System.out.println("**********************************************"); System.out.println("difference"); System.out.println("**********************************************"); HashSet<Long> set1 = Sets.newHashSet(); HashSet<Long> set2 = Sets.newHashSet(); for (int i = 1; i < 12; i++) { set1.add((long) i); } for (int i = 5; i < 20; i++) { set2.add((long) i); } System.out.println("reference " + Sets.difference(set1, set2)); System.out.println("reference " + Sets.difference(set2, set1)); LongSet longset1 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set1)); LongSet longset2 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set2)); LongSet diff1 = LongSets.difference(longset1, longset2); LongSet diff2 = LongSets.difference(longset2, longset1); System.out.println("assert " + diff1); System.out.println("assert " + diff2); System.out.println("*******************************************"); set1 = Sets.newHashSet(); set2 = Sets.newHashSet(); for (int i = 1; i < 3500000; i++) { set1.add((long) i); } for (int i = 500000; i < 4000000; i++) { set2.add((long) i); } long t = System.currentTimeMillis(); System.out.println(Sets.difference(set1, set2).size()); System.out.println(Sets.difference(set2, set1).size()); StopWatch.time("diff sets", t); longset1 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set1)); longset2 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set2)); t = System.currentTimeMillis(); diff1 = LongSets.difference(longset1, longset2); diff2 = LongSets.difference(longset2, longset1); System.out.println(diff1.size()); System.out.println(diff2.size()); StopWatch.time("diff longsets", t); System.out.println("**********************************************"); System.out.println("intersection"); System.out.println("**********************************************"); set1 = Sets.newHashSet(); set2 = Sets.newHashSet(); for (int i = 1; i < 12; i++) { set1.add((long) i); } for (int i = 5; i < 20; i++) { set2.add((long) i); } System.out.println("reference " + Sets.intersection(set1, set2)); System.out.println("reference " + Sets.intersection(set2, set1)); longset1 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set1)); longset2 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set2)); LongSet intersection1 = LongSets.intersection(longset1, longset2); LongSet intersection2 = LongSets.intersection(longset2, longset1); System.out.println("assert " + intersection1); System.out.println("assser " + intersection2); System.out.println("*******************************************"); set1 = Sets.newHashSet(); set2 = Sets.newHashSet(); for (int i = 1; i < 3500000; i++) { set1.add((long) i); } for (int i = 500000; i < 4000000; i++) { set2.add((long) i); } t = System.currentTimeMillis(); System.out.println(Sets.intersection(set1, set2).size()); System.out.println(Sets.intersection(set2, set1).size()); StopWatch.time("intersection sets", t); longset1 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set1)); longset2 = PrimitiveSets.newLongOpenHashSet(Longs.toArray(set2)); t = System.currentTimeMillis(); intersection1 = LongSets.intersection(longset1, longset2); intersection2 = LongSets.intersection(longset2, longset1); System.out.println(intersection1.size()); System.out.println(intersection2.size()); StopWatch.time("intersection longsets", t); } }