对List进行非固定下标的随机平均分组

对List进行非固定下标的随机平均分组

前提

项目中用到了一个调度算法,会对List中的任务平均分组到不同的集群中,之前的思路是平均取余数,然后将余数加到最后一个分片中,这样资源有很大的浪费。因为最后的余数可以加到之前的所有的分片当中,而不必是最后一个。网上有一个流传度交广的算法是将余数分配到了前几个切片中,这样在调度比较频繁的时候,前几个人集群负载会较大,造成负载不均。现在的改进是将余数随机分配到不同的分片中。

源码

  private static final Random JVM_RANDOM = new JVMRandom();

    /**
     * 将一个list均分成n个list,主要通过偏移量来实现的,改进版
     * 对分片的算法作改进,如果是10个平分成4片,则A/B会分到3片,C/D分到2片,负载会更加均衡
     * 现在改进后的remainder会随机加到平均后的分组list中
     * @param source
     * @return
     */
    public static <T> List<List<T>> average(final List<T> source, final int n) {
        if (source == null) {
            throw new NullPointerException("List must not be null");
        }
        if (n <= 0) {
            throw new IllegalArgumentException("Size must be greater than 0");
        }
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n; // (先计算出余数)
        int number = source.size() / n; // 然后是商
        int offset = 0;// 偏移量

        int[] idxs = Arrays.stream(buildNoRepeatIndex(n), 0, remaider).sorted().toArray();
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0 && containsInts(idxs, i)) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }

    /**
     * 创建不重复的数组下标
     * @param source
     * @return
     */
    public static int[] buildNoRepeatIndex(int size) {
        int values[] = new int[size];
        int temp1, temp2, temp3;

        for (int i = 0; i < size; i++) {
            values[i] = i;
        }

        // 随机交换values.length次
        for (int i = 0; i < size; i++) {
            temp1 = JVM_RANDOM.nextInt(size); // 随机产生一个位置
            temp2 = JVM_RANDOM.nextInt(size); // 随机产生另一个位置

            if (temp1 != temp2) {
                temp3 = values[temp1];
                values[temp1] = values[temp2];
                values[temp2] = temp3;
            }
        }

        return values;
    }

    private static boolean containsInts(int[] array, int target) {
        for (int value : array) {
            if (value == target) {
                return true;
            }
        }
        return false;
    } 
在C#中,如果你想要将一个List按照某个条件随机分成几个小,可以使用`System.Linq`库中的`GroupBy`和`Random`类。首先,你需要定义一个条件函数来确定哪些元素应该属于同一,然后创建一个随机数生成器,最后使用`Random.Next()`函数来决定每个元素所属的。 以下是一个简单的示例,假设我们有一个学生列表,你想根据他们的分数将其随机分为高分组、中等分组和低分组: ```csharp using System; using System.Collections.Generic; using System.Linq; class Student { public int Score { get; set; } } public class Program { static void Main(string[] args) { List<Student> students = new List<Student>(); // 假设填充了学生的列表 // 定义分组条件(这里设置为得分范围) Func<Student, string> groupFunction = student => student.Score >= 90 ? "高分组" : (student.Score >= 60 && student.Score < 90) ? "中等分组" : "低分组"; // 创建随机数生成器 Random random = new Random(); // 按照条件分组,并随机分配到三个队列 var groups = students.GroupBy(groupFunction) .Select(group => { var randomIndex = random.Next(3); // 生成0-2之间的随机整数 if (randomIndex == 0) return group.ToList(); // 高分组 else if (randomIndex == 1) return group.Skip(1).Take(group.Count / 2).ToList(); // 中等分组 else return group.Skip(group.Count / 2).ToList(); // 低分组 }) .ToList(); foreach (var group in groups) { Console.WriteLine($"名: {group.Key}, 学生: {string.Join(", ", group.Select(s => s.Score))}"); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值