1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.rng.sampling; 19 20 import java.util.List; 21 import java.util.ArrayList; 22 23 import org.apache.commons.rng.UniformRandomProvider; 24 25 /** 26 * Sampling from a {@link List}. 27 * 28 * This class also contains utilities for shuffling a {@link List} in-place. 29 * 30 * @since 1.0 31 */ 32 public class ListSampler { 33 /** 34 * Class contains only static methods. 35 */ 36 private ListSampler() {} 37 38 /** 39 * Generates a list of size {@code k} whose entries are selected 40 * randomly, without repetition, from the items in the given 41 * {@code collection}. 42 * 43 * <p> 44 * Sampling is without replacement; but if the source collection 45 * contains identical objects, the sample may include repeats. 46 * </p> 47 * 48 * @param <T> Type of the list items. 49 * @param rng Generator of uniformly distributed random numbers. 50 * @param collection List to be sampled from. 51 * @param k Size of the returned sample. 52 * @throws IllegalArgumentException if {@code k <= 0} or 53 * {@code k > collection.size()}. 54 * @return a shuffled sample from the source collection. 55 */ 56 public static <T> List<T> sample(UniformRandomProvider rng, 57 List<T> collection, 58 int k) { 59 final int n = collection.size(); 60 final PermutationSampler p = new PermutationSampler(rng, n, k); 61 final List<T> result = new ArrayList<T>(k); 62 final int[] index = p.sample(); 63 64 for (int i = 0; i < k; i++) { 65 result.add(collection.get(index[i])); 66 } 67 68 return result; 69 } 70 71 /** 72 * Shuffles the entries of the given array. 73 * 74 * @see #shuffle(UniformRandomProvider,List,int,boolean) 75 * 76 * @param <T> Type of the list items. 77 * @param rng Random number generator. 78 * @param list List whose entries will be shuffled (in-place). 79 */ 80 public static <T> void shuffle(UniformRandomProvider rng, 81 List<T> list) { 82 shuffle(rng, list, 0, false); 83 } 84 85 /** 86 * Shuffles the entries of the given array, using the 87 * <a href="http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_modern_algorithm"> 88 * Fisher-Yates</a> algorithm. 89 * The {@code start} and {@code pos} parameters select which part 90 * of the array is randomized and which is left untouched. 91 * 92 * @param <T> Type of the list items. 93 * @param rng Random number generator. 94 * @param list List whose entries will be shuffled (in-place). 95 * @param start Index at which shuffling begins. 96 * @param towardHead Shuffling is performed for index positions between 97 * {@code start} and either the end (if {@code false}) or the beginning 98 * (if {@code true}) of the array. 99 */ 100 public static <T> void shuffle(UniformRandomProvider rng, 101 List<T> list, 102 int start, 103 boolean towardHead) { 104 final int len = list.size(); 105 final int[] indices = PermutationSampler.natural(len); 106 PermutationSampler.shuffle(rng, indices, start, towardHead); 107 108 final ArrayList<T> items = new ArrayList<T>(list); 109 for (int i = 0; i < len; i++) { 110 list.set(i, items.get(indices[i])); 111 } 112 } 113 }