// Path: src/main/java/be/fror/common/base/Preconditions.java
// public static <T> T checkArgument(@Nullable T value, Predicate<? super T> predicate) {
//   if (predicate.test(value)) {
//     return value;
//   } else {
//     throw new IllegalArgumentException();
//   }
// }


import static be.fror.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static java.util.Spliterator.IMMUTABLE;
import static java.util.Spliterator.ORDERED;
import java.util.Collection;
import java.util.Iterator;
import java.util.Random;
import java.util.Spliterators;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.concurrent.ThreadSafe;
/*
 * Copyright 2015 Olivier Grégoire.
 *
 * 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 be.fror.common.collection;




/**
 * A tool to randomly select elements from collections.
 *
 * <p>
 * Example usages:
 *
 * <pre><code>
 * Random random = ...
 * Map&lt;String, Double&gt; stringWeights = new Hash&lt;&gt;();
 * stringWeights.put("a", 4d);
 * stringWeights.put("b", 3d);
 * stringWeights.put("c", 12d);
 * stringWeights.put("d", 1d);
 *
 * RandomSelector&lt;String&gt; selector = RandomSelector.weighted(stringWeights.keySet(), s -&gt; stringWeights.get(s));
 * List&lt;String&gt; selection = new ArrayList&lt;&gt;();
 * for (int i = 0; i &lt; 10; i++) {
 *   selection.add(selector.next(random));
 * }
 * </code></pre>
 *
 *
 * @author Olivier Grégoire
 * @param <T>
 */
@ThreadSafe
public final class RandomSelector<T> {

  /**
   * Creates a new random selector based on a uniform distribution.
   *
   * <p>
   * A copy of <tt>elements</tt> is kept, so any modification to <tt>elements</tt> will not be
   * reflected in returned values.
   *
   * @param <T>
   * @param elements
   * @return
   * @throws IllegalArgumentException if <tt>elements</tt> is empty.
   */
  public static <T> RandomSelector<T> uniform(final Collection<T> elements)
      throws IllegalArgumentException {
    requireNonNull(elements, "collection must not be null");
// Path: src/main/java/be/fror/common/base/Preconditions.java
// public static <T> T checkArgument(@Nullable T value, Predicate<? super T> predicate) {
//   if (predicate.test(value)) {
//     return value;
//   } else {
//     throw new IllegalArgumentException();
//   }
// }


// Path: src/main/java/be/fror/common/collection/RandomSelector.java
import static be.fror.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static java.util.Spliterator.IMMUTABLE;
import static java.util.Spliterator.ORDERED;
import java.util.Collection;
import java.util.Iterator;
import java.util.Random;
import java.util.Spliterators;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.concurrent.ThreadSafe;

/*
 * Copyright 2015 Olivier Grégoire.
 *
 * 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 be.fror.common.collection;




/**
 * A tool to randomly select elements from collections.
 *
 * <p>
 * Example usages:
 *
 * <pre><code>
 * Random random = ...
 * Map&lt;String, Double&gt; stringWeights = new Hash&lt;&gt;();
 * stringWeights.put("a", 4d);
 * stringWeights.put("b", 3d);
 * stringWeights.put("c", 12d);
 * stringWeights.put("d", 1d);
 *
 * RandomSelector&lt;String&gt; selector = RandomSelector.weighted(stringWeights.keySet(), s -&gt; stringWeights.get(s));
 * List&lt;String&gt; selection = new ArrayList&lt;&gt;();
 * for (int i = 0; i &lt; 10; i++) {
 *   selection.add(selector.next(random));
 * }
 * </code></pre>
 *
 *
 * @author Olivier Grégoire
 * @param <T>
 */
@ThreadSafe
public final class RandomSelector<T> {

  /**
   * Creates a new random selector based on a uniform distribution.
   *
   * <p>
   * A copy of <tt>elements</tt> is kept, so any modification to <tt>elements</tt> will not be
   * reflected in returned values.
   *
   * @param <T>
   * @param elements
   * @return
   * @throws IllegalArgumentException if <tt>elements</tt> is empty.
   */
  public static <T> RandomSelector<T> uniform(final Collection<T> elements)
      throws IllegalArgumentException {
    requireNonNull(elements, "collection must not be null");
    checkArgument(!elements.isEmpty(), "collection must not be empty");