一個數組通過配置隨機抽取組成小數組

1.場景

現有一個數組,想抽出其中一部分元素組成另外一個小一點的數組,又不希望完全隨機抽出,比如希望原數組的前20%抽多點,中間的50%少抽點,最後的30%再多抽點,而且希望在範圍內是不重複隨機抽取

2.思路
將不同的配置,轉化成固定要取的數量的區域,再從不同的區域裏使用不重複隨機算法取

3.Java Code

package kowalski;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Created by kowalski.zhang on 2018/6/6
 */
public final class PickUtil {

  private static Random random = ThreadLocalRandom.current();

  private PickUtil() {
  }

  /***
   * just pick with config
   * @param srcList
   * @param configs
   * @param <T>
   * @return
   */
  public static <T> List<T> levelPickWithNewByConfig(List<T> srcList, Double[]... configs) {

    if (srcList == null || srcList.isEmpty()) {
      return Collections.emptyList();
    }
    List<T> res = new ArrayList<>(srcList.size());

    int lastIndex = 0;
    for (Double[] config : configs) {

      int modelLen = config[0].intValue();
      /**獲取長度大於等於有效長度 全額取出*/
      if (modelLen <= config[1]) {
        for (int m = 0; m < modelLen; m++) {
          res.add(srcList.get(lastIndex + m));
        }
      } else {
        /**區域內使用不重複隨機算法pick*/
        int randLen = config[1].intValue();
        int tempModelLen = modelLen;
        for (int m = 0; m < randLen; m++) {
          int randNum = random.nextInt(tempModelLen);
          res.add(srcList.get(randNum + lastIndex));
          tempModelLen--;
        }
      }
      lastIndex += modelLen;
    }

    return res;
  }

  /**
   * pick
   * @param srcList
   * @param configs 取出配置
   * @param pickNum 最大取出量
   * @param <T>
   * @return
   */
  public static <T> List<T> levelPickWithNew(List<T> srcList, Double[][] configs, ConfigTypeEnum typeEnum, Integer pickNum) {
    if (pickNum < srcList.size()) {
      return srcList;
    }

    switch (typeEnum){
      case FIXED_FIXED:
        return levelPickWithNewByConfig(srcList, configs);
      case JUST_PERCENT:
        return levelPickWithNewByConfig(srcList, exchangeConfigToFixNum(srcList.size(), configs));
      case PERCENT_FIXED:
        return levelPickWithNewByConfig(srcList, exchangeConfigToFixNum(srcList.size(), pickNum, configs));
    }
    return srcList;
  }

  public static <T> List<T> levelPickWithNew(List<T> srcList, Double[][] configs, ConfigTypeEnum typeEnum) {
    return levelPickWithNew(srcList, configs, typeEnum, null);
  }

  /**
   * 將ConfigTypeEnum.PERCENT_FIXED轉化成對應的FIXED_FIXED配置
   * @param listLen
   * @param configs
   * @return
   */
  public static Double[][] exchangeConfigToFixNum(int listLen, Double[]... configs) {
    Double[][] res = new Double[configs.length][configs[0].length];
    int total = 0;
    for (int i = 0; i < configs.length - 1; i++) {
      int temp = (int) (configs[i][0] * listLen);
      total += temp;
      res[i][0] = (double) temp;
    }
    /**最後一個配置收拾殘局*/
    if (listLen > total) {
      res[configs.length - 1][0] = (double) (listLen - total);
    }
    return res;
  }

  /***
   * ConfigTypeEnum.JUST_PERCENT轉化成對應的FIXED_FIXED配置
   * @param listLen
   * @param pickNum
   * @param configs
   */
  public static Double[][] exchangeConfigToFixNum(int listLen, Integer pickNum, Double[]... configs) {

    if (pickNum == null || pickNum < 0) {
      throw new RuntimeException("pickNum not leagal !!!");
    }
    Double[][] res = new Double[configs.length][configs[0].length];
    int total = 0;
    int totalPick = 0;
    for (int i = 0; i < configs.length - 1; i++) {
      int temp = (int) (configs[i][0] * listLen);
      int tempPick = (int) (configs[i][0] * pickNum);
      total += temp;
      totalPick += tempPick;
      res[i][0] = (double) temp;
      res[i][1] = (double) tempPick;
    }
    /**最後一個配置收拾殘局*/
    if (listLen > total) {
      res[configs.length - 1][0] = (double) (listLen - total);
    }
    if (pickNum > totalPick) {
      res[configs.length - 1][1] = (double) (pickNum - totalPick);
    }

    return res;
  }

  public enum ConfigTypeEnum {

    PERCENT_FIXED(1, "百分比-固定量"),
    FIXED_FIXED(2, "固定量-固定量"),
    JUST_PERCENT(4, "僅百分比"),;//必須傳期待List大小(pickNum)

    private Integer type;
    private String desc;

    ConfigTypeEnum(Integer type, String desc) {
      this.type = type;
      this.desc = desc;
    }

    public Integer getType() {
      return type;
    }

    public void setType(Integer type) {
      this.type = type;
    }

    public String getDesc() {
      return desc;
    }

    private static final Map<Integer, ConfigTypeEnum> map = new HashMap<>();

    static {
      for (ConfigTypeEnum enums : ConfigTypeEnum.values()) {
        map.put(enums.getType(), enums);
      }
    }

    public static ConfigTypeEnum getEnumValue(int code) {
      return map.get(code);
    }

    public static String getDescByType(int code) {
      return map.get(code).getDesc();
    }

    public void setDesc(String desc) {
      this.desc = desc;
    }

  }


  public static void main(String... args) {

    Double[][] configs = { { 0.15d, 10.0d }, { 0.25d, 15.0d }, { 0.6d, 30.0d } };

    ConfigTypeEnum configType = ConfigTypeEnum.PERCENT_FIXED;
  }
}

有更好方式的小夥伴歡迎交流~~
e:[email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章