随机分配人员分组
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))
您正在以一种确定性的方式对您的伙伴进行排序,从而有效地撤销之前的洗牌。这就是为什么你每次都得到相同的组。
我正在开发群组生成器并使用此方法对人员进行分组
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))
您正在以一种确定性的方式对您的伙伴进行排序,从而有效地撤销之前的洗牌。这就是为什么你每次都得到相同的组。