【问题标题】:Randomly distribute people in groups将人员随机分组
【发布时间】:2020-08-17 12:18:05
【问题描述】:

我正在开发组生成器并使用此方法对人员进行分组

public String nMix(String file, int numOfGroups) {
   ReadFile info = new ReadFile();
   ArrayList<String> studentInfo = info.readEachWord(file);

   List<PeopleClass> people = new ArrayList<PeopleClass>();
   for (int i = 0; i < studentInfo.size(); i += 4) {
      people.add(new PeopleClass(studentInfo.get(i))); //name
   }

   Collections.shuffle(people);
// System.out.println(people.get(0).getName());

   Function<PeopleClass, String> discriminator = PeopleClass::getName;
   AtomicInteger index = new AtomicInteger();
   List<List<PeopleClass>> groups = new ArrayList<>(people.stream()
      .sorted(Comparator.comparing(discriminator))
      .collect(Collectors.groupingBy(e -> index.getAndIncrement() % numOfGroups))
      .values());

   //groups.forEach(System.out::println);
   groups.forEach(System.out::println);
   String txt = "";

   for(int j = 0; j < groups.size(); j ++) {
      txt += "Group" + (j + 1);
      txt += "\r\n";
      txt += groups.get(j);
      txt += "\r\n";
      txt += "\r\n";
   }

   return txt;
}

我的人班

public PeopleClass(String name){
   this.name = name;
}

但是每次我使用它时,这些组似乎不是随机的,而是按照原始 ArrayList 名称的顺序进行分组。我应该如何解决这个问题并使其随机化。

【问题讨论】:

  • 洗牌后为什么要打电话给.sorted(Comparator.comparing(discriminator))

标签: java arraylist random shuffle


【解决方案1】:

这是一种方法。

    final int numOfGroups = 3;

    List<String> names = Arrays.asList("Nielsen", "Jensen", "Hansen",
            "Pedersen", "Andersen", "Christensen", "Larsen", "Sørensen");
    Collections.shuffle(names);
    List<List<String>> groups = IntStream.range(0, names.size())
            .boxed()
            .collect(Collectors.groupingBy(i -> i % numOfGroups))
            .values()
            .stream()
            .map(il -> il.stream().map(names::get).collect(Collectors.toList()))
            .collect(Collectors.toList());

    groups.forEach(System.out::println);

为了简单的演示,我只是在这里将字符串随机分配到组中。它与PeopleClass 对象相同。示例输出:

[Larsen, Jensen, Sørensen]
[Nielsen, Christensen, Hansen]
[Andersen, Pedersen]

我不喜欢有副作用的流操作。这就是为什么在我的第一个流操作中,我只处理洗牌列表中的索引,将它们分配到组中。这使我可以在不参考流操作之外的任何内容的情况下进行模运算。在形成索引列表后,我将每个这样的列表转换为名称列表,并在新的流操作中对第一个列表的结果进行操作。

你的代码出了什么问题?

正如其他人所说,这条线是罪魁祸首:

      .sorted(Comparator.comparing(discriminator))

您正在以一种确定性的方式对您的员工进行排序,从而有效地撤消了之前的洗牌。这就是为什么你每次都得到相同的组。

【讨论】:

    【解决方案2】:

    我能够重现并运行您的代码并获得预期的结果。 我只需要进行一些更改:

    1)在您的初始 for 循环中,您将 i 增加 4:
    for (int i = 0; i < studentInfo.size(); i += 4) {
    

    我不知道您为什么要这样做,导致您跳过将学生从文件添加到列表中,所以我将其更改为将 i 加 1:

    for (int i = 0; i < studentInfo.size(); i++) {
    

    2) Collections.shuffle() 调用按预期工作,如果在调用后直接打印混洗列表,您会得到类似的结果并打印列表,您可以看到它们已正确混洗。

    最后,您不应该在您的 Lamda 中调用 .sorted(),这将再次对列表进行排序,从而违背了调用 Collections.shuffle() 的目的:

        Function<PeopleClass, String> discriminator = PeopleClass::getName;
        AtomicInteger index = new AtomicInteger();
        List<List<PeopleClass>> groups = new ArrayList<>(people.stream()
              //  .sorted(Comparator.comparing(discriminator))
                .collect(Collectors.groupingBy(e -> (index.getAndIncrement() % numOfGroups)))
                .values()
        );
    

    最后,在您的PersonClass 中覆盖toString() 方法也很有帮助(最好直接称它为Person)。通过覆盖toString(),您可以只返回该人的姓名,从而打印出整个列表可读。

    以下是您的课程的最终修改版本:

    public String nMix(String file, int numOfGroups) {
       ReadFile info = new ReadFile();
       ArrayList<String> studentInfo = info.readEachWord(file);
    
       List<PeopleClass> people = new ArrayList<PeopleClass>();
       for (int i = 0; i < studentInfo.size(); i++) {
          people.add(new PeopleClass(studentInfo.get(i))); //name
       }
    
       Collections.shuffle(people);
       System.out.println("Shuffled people: " + people);
    
       Function<PeopleClass, String> discriminator = PeopleClass::getName;
       AtomicInteger index = new AtomicInteger();
       List<List<PeopleClass>> groups = new ArrayList<>(people.stream()
          //.sorted(Comparator.comparing(discriminator))
          .collect(Collectors.groupingBy(e -> index.getAndIncrement() % numOfGroups))
          .values());
    
       //groups.forEach(System.out::println);
       groups.forEach(System.out::println);
       String txt = "";
    
       for(int j = 0; j < groups.size(); j ++) {
          txt += "Group" + (j + 1);
          txt += "\r\n";
          txt += groups.get(j);
          txt += "\r\n";
          txt += "\r\n";
       }
    
       return txt;
    }
    

    人物类:

    class PeopleClass {
       String name;
    
       public PeopleClass(String name) {
          this.name = name;
       }
    
       public String getName(){
          return this.name;
       }
    
       @Override
       public String toString() {
          return this.name;
       }
    }
    

    输入:我没有您的输入文件内容,因此使用示例列表:{"p1","p2","p3","p4","p5","p6","p7","p8","p9","p10"}

    输出:

    洗牌的人:[p8, p4, p7, p6, p9, p1, p3, p2, p5, p10]

    组 1 [p8, p6, p3, p10]

    Group2 [p4, p9, p2]

    Group3 [p7, p1, p5]

    【讨论】:

    • 嘿,我增加了 4,因为我的数组列表包含不同的信息,所以每四个都是人名,抱歉我没有提到这个@pczeus
    • 代码在摆脱排序后完美运行!!我想是因为我为我的其他一些排序算法复制了相同的方法,却忘了调整那部分!!谢谢你的详细解释,真的很有帮助!! @pczeus
    猜你喜欢
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    相关资源
    最近更新 更多