Случайно распределить людей по группам - PullRequest
1 голос
/ 03 мая 2020

Я работаю над генератором групп и использую этот метод для группировки людей

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 имен. Как мне это исправить и сделать случайным.

Ответы [ 2 ]

3 голосов
/ 03 мая 2020

Вот один из способов.

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

Вы сортируете своих людей определенным образом c, тем самым эффективно уничтожая предыдущую случайную последовательность. Вот почему вы получаете одни и те же группы каждый раз.

1 голос
/ 03 мая 2020

Мне удалось воспроизвести и запустить ваш код и получить ожидаемые результаты. Мне нужно было всего лишь внести несколько изменений:

1) В вашем начальном для l oop вы увеличиваете i на 4:
for (int i = 0; i < studentInfo.size(); i += 4) {

Я не знаю, почему вы это сделали, в результате чего вы пропускаете добавление учеников из вашего файла в список, поэтому я изменил его, увеличив значение i на 1:

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

2) Вызов Collections.shuffle () работает, как ожидалось, и при печати перемешанного список сразу после звонка вы получите что-то вроде и распечатав список, вы увидите, что они правильно перетасованы.

И, наконец, вам не следует звонить .sorted() в вашей Lamda, которая снова упорядочит список, побеждая цель вызова 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()
    );

Наконец также полезно переопределить метод toString() в вашем PersonClass (было бы лучше просто вызвать его 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]

Group1 [p8, p6, p3, p10]

Group2 [p4, p9, p2]

группа 3 [p7, p1, p5]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...