其中的关键在于:每次循环随机获得一个下标,如果是首次访问到这个下标,将这个元素抽出到返回结果数组中,然后让这个数组下标index对应的元素引用一个其他任意对象srcNoContain(数组或集合不包含此对象)。如果下次循产生的随机下标index对应的元素与srcNoContain相等,表明这个下标已经被访问,这个下标对应的元素已经被抽取过了,不能再抽取它了。那么就要再进行循环获取新的随机下标,直到这个下标index对应的元素与srcNoContain不等时,就可以抽出一个这个下标对应的元素。
import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Random; public class RandomUtil { private static final Random random; static { random = new Random(); } /** * 从List集合中随机抽取指定数量的非重复元素 * <p>注意:集合中不能有null元素,否则返回值中可能有重复的元素 * @param src List集合源 * @param chooseCount 抽取的元素个数 * @return * @see [类、类#方法、类#成员] */ public static <T> List<T> randomChooseElements(List<T> src, int chooseCount) { return randomChooseElements(src, chooseCount, null); } /** * 从List集合中随机抽取指定数量的非重复元素 * @param src List集合源 * @param chooseCount 抽取的元素个数 * @param srcNoContain 集合源中不包含的任意对象 * @return * @see [类、类#方法、类#成员] */ public static <T> List<T> randomChooseElements(List<T> src, int chooseCount, T srcNoContain) { for (Object element : src) { if (element == srcNoContain) { throw new IllegalStateException("指定的不同元素srcNoContain与参数src中的某一个元素相同"); } } if (chooseCount > src.size()) { throw new IllegalArgumentException("参数chooseCount不能大于集合src的元素个数."); } int sizeOfCopiedList = src.size(); List<T> copiedList = new ArrayList<T>(src); List<T> choosedList = new ArrayList<T>(); int index = -1; for (int i = 0; i < chooseCount; i++) { while (true) { index = random.nextInt(sizeOfCopiedList); if (copiedList.get(index) != srcNoContain) { choosedList.add(copiedList.get(index)); copiedList.set(index, srcNoContain); break; } } } return choosedList; } /** * 从数组中随机抽取指定数量的非重复元素 * <p>注意:数组中不能有null元素,否则返回值中可能有重复的元素 * @param src 数组源 * @param chooseCount 抽取的元素个数 * @return * @see [类、类#方法、类#成员] */ public static Object[] randomChooseElements(Object[] src, int chooseCount) { return randomChooseElements(src, chooseCount, null); } /** * 从数组中随机抽取指定数量的非重复元素 * @param src 数组源 * @param chooseCount 抽取的元素个数 * @param srcNoContain 源数组不包含的(类类型与数组的元素类型相同)任意对象 * @return * @see [类、类#方法、类#成员] */ public static Object[] randomChooseElements(Object[] src, int chooseCount, Object srcNoContain) { for (Object element : src) { if (element == srcNoContain) { throw new IllegalStateException("指定的不同元素srcNoContain与参数src中的某一个元素相同"); } } if (chooseCount > src.length) { throw new IllegalArgumentException("参数chooseCount不能大于数组参数src的长度."); } Object[] copiedArray = Arrays.copyOf(src, src.length); Object[] choosedArray = new Object[chooseCount]; int index = -1; for (int i = 0; i < choosedArray.length; i++) { while (true) { index = random.nextInt(copiedArray.length); if (copiedArray[index] != srcNoContain) { choosedArray[i] = copiedArray[index]; copiedArray[index] = srcNoContain; break; } } } return choosedArray; } public static void main(String[] args) { List<Date> dates1 = Arrays.asList(new Date(119, 7, 21), new Date(119, 3, 12), new Date(119, 9, 7), new Date(119, 3, 23)); List<Date> selectDates = randomChooseElements(dates1, 3); System.out.println("源集合是:"+dates1); System.out.println("集合中随机抽取的元素:"+selectDates); System.out.println(); Date[] dates = new Date[] {new Date(119, 7, 21), new Date(119, 3, 12), new Date(119, 9, 7), new Date(119, 3, 23)}; Object[] arr1 = randomChooseElements(dates, 2); System.out.println("源数组是"+Arrays.toString(dates)); System.out.println("数组中随机选择出来元素" + Arrays.toString(arr1)); } }
控制台输出
另外,其实JDK自带的Collections工具类提供了两个随机打乱集合的方法shuffle(List<?> list) 与shuffle(List<?> list, Random rnd) ,经过一此处理变通后,数组和集合都可以用这两个静态方法处理。
Date[] dates = new Date[] {new Date(119, 7, 21), new Date(119, 3, 12), new Date(119, 9, 7), new Date(119, 3, 23)}; List<Date> copiedDates=new ArrayList<Date>( Arrays.asList(Arrays.copyOf(dates, dates.length))); Collections.shuffle(copiedDates); System.out.println(copiedDates); System.out.println("原"+Arrays.toString(dates));