從list中取N個隨機生成一個集合


在工作中發現有很多有序算法,較少見到一些可用的無序隨機算法。無序隨機算法的目的是讓客戶感覺每次都不一樣,因為一直看一樣的會審美疲勞哈。

在jdk自帶一種CollectionUtils.shuffle<List<?> list> 使用默認隨機源對指定列表進行置換,方便快捷。熟讀JDK是如此的重要。

一下兩種算法適用於一些特殊場合

特意寫了兩種算法。一種是利用set集合的特性,加上優化,因為如果list的個數不大,要在list中取的個數比較多的情況下,采用逆向生成算法,最佳適用於大數據量選取少量隨機元素。

另外一種是隨機置換位置法,每一個位置都有一次換位的機會,最佳適用於小數據量選取大量隨機元素。

有好的意見可以分享給我哈。

package com.duotin.japi.common.utils;

import com.duotin.util.CollectionUtils;
import org.apache.commons.lang.math.RandomUtils;

import java.util.*;

/**
 * 生成隨機集合工具類
 * 
 */
public class RandomDataUtil {
    public final static int TWO=2;
    /**
     * 生成隨機集合(不重復)
     * <p>
     *     使用Set的值唯一的特性。
     *     最佳適用場合:集合中數目多,取相對較少對象時。在取對象相對較多時(超過集合的一半時)采用逆向方法,
     *                在取得對象個數是集合總數的1/2左右時是效率最慢的。
     * </p>
     * @param list
     * @param generateNum 生成集合中元素的個數
     * @param <T>
     * @return
     */
    public <T> List<T> generateRandomDataNoRepeat(List<T> list,Integer generateNum){
        List<T> tList = new ArrayList<T>();
        if(CollectionUtils.isNotEmpty(list)) {
            for (Integer num : generateRandomNoRepeat(list.size(), generateNum)) {
                tList.add(list.get(num));
            }
        }
        return tList;
    }

    /**
     * 生成隨機集合,隨機置換位置、隨機截取位置法。
     * <p>
     *     隨機置換法:將集合的每個位置值與隨機位置的值調換,並隨機截取位置.
     *     最佳適合場合:集合的數量相對較少,獲取較多的隨機個數集合。
     * </p>
     * @param list
     * @param generateNum
     * @param <T>
     * @return
     */
    public <T> List<T> generateRandomPermutation(List<T> list,Integer generateNum){
        if(CollectionUtils.isNotEmpty(list)) {
            checkParams(list.size(),generateNum);
            List<T> randomAllList = randomPermutation(list, generateNum);
            int initPosition=interceptPosition(list.size(),generateNum);
            return randomAllList.subList(initPosition,initPosition+generateNum);
        }
        return Collections.emptyList();
    }

    /**
     * 隨機置換算法
     * @param list
     * @param generateNum
     * @param <T>
     * @return
     */
    private <T> List<T> randomPermutation(List<T> list,Integer generateNum){
        for (int i = 0; i < list.size(); i++) {
            Integer random=RandomUtils.nextInt(list.size());
            T t = list.get(random);
            list.set(random,list.get(i));
            list.set(i,t);
        }
        return list;
    }

    /**
     * 隨機生成截取位置
     * @param totalCount
     * @param generateNum
     * @return
     */
    private Integer interceptPosition(Integer totalCount,Integer generateNum){
        int num=RandomUtils.nextInt(totalCount);
        if(num+generateNum>totalCount){
            num=num-generateNum;
        }
        return  num;
    }
    /**
     * 生成不重復的隨機數
     * @param totalCount
     * @param generateNum
     * @param
     * @return
     */
    public Set<Integer> generateRandomNoRepeat(Integer totalCount,Integer generateNum){
        if(isLessThanHalfTotalCount(totalCount,generateNum)){
            return getRandomNoRepeat(totalCount,generateNum);
        }
        return getReverseRandomNoRepeat(totalCount,generateNum);
    }

    /**
     * 驗證參數是否合法
     * @param totalCount
     * @param generateNum
     */
    private void checkParams(Integer totalCount,Integer generateNum){
        if(totalCount<generateNum){
            throw new IllegalArgumentException("generateNum is out of totalCount");
        }
    }

    /**
     * 判斷使用哪種生成機制
     * @param totalCount
     * @param generateNum
     * @return
     */
    private Boolean isLessThanHalfTotalCount(Integer totalCount,Integer generateNum){
        if(generateNum<totalCount/TWO){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 生成set,不重復
     * @param totalCount
     * @param generateNum
     * @return
     */
    private Set<Integer> getRandomNoRepeat(Integer totalCount,Integer generateNum){
        Set<Integer> set = new HashSet<Integer>();
        while (true) {
            set.add(RandomUtils.nextInt(totalCount));
            if(set.size() == generateNum){
                return set;
            }
        }
    }

    /**
     * 逆向生成set,不重復
     * @param totalCount
     * @param generateNum
     * @return
     */
    private Set<Integer> getReverseRandomNoRepeat(Integer totalCount,Integer generateNum){
        Set<Integer> set = new HashSet<Integer>();
        while (true) {
            set.add(RandomUtils.nextInt(totalCount));
            if(set.size() == totalCount-generateNum){
                Set<Integer> setALL=getSetALL(totalCount);
                setALL.removeAll(set);
                return setALL;
            }
        }
    }

    /**
     * 生成Set
     * @param totalCount
     * @return
     */
    private Set<Integer> getSetALL(Integer totalCount){
        Set<Integer> set = new HashSet<Integer>();
        for(int i=0;i<totalCount;i++){
            set.add(i);
        }
        return set;
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM