其中的关键在于:每次循环随机获得一个下标,如果是首次访问到这个下标,将这个元素抽出到返回结果数组中,然后让这个数组下标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));