随机分配人员分组

Randomly distribute people in groups

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

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;
}

我的人class

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

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

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

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(),您可以 return 仅此人的姓名,从而使打印出的整个列表可读。

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

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:

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"}

输出:

Shuffled people: [p8, p4, p7, p6, p9, p1, p3, p2, p5, p10]

Group1 [p8, p6, p3, p10]

Group2 [p4, p9, p2]

Group3 [p7, p1, p5]

这是一种方法。

    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))

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