一个数组通过配置随机抽取组成小数组

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 
   * @return
   */
  public static  List levelPickWithNewByConfig(List srcList, Double[]... configs) {

    if (srcList == null || srcList.isEmpty()) {
      return Collections.emptyList();
    }
    List 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 
   * @return
   */
  public static  List levelPickWithNew(List 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  List levelPickWithNew(List 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 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]

你可能感兴趣的:(算法)