-4

I have the following dummy table.

+----+-------+-------+-----+--------+
| Id |Marks  |Grade  |GId  |Gender  |
+----+-------+-------+-----+--------+
| 1  | 95    | S     | 1   | 1      |
| 2  | 95    | S     | 1   | 0      |
| 3  | 93    | S     | 1   | 0      |
| 4  | 75    | B     | 3   | 1      |
| 5  | 74    | B     | 3   | 1      |
| 6  | 83    | A     | 2   | 0      |
| 7  | 83    | A     | 2   | 0      |
| 8  | 83.5  | A     | 2   | 0      |
| 9  | 70    | B     | 3   | 0      |
| 10 | 71    | B     | 3   | 1      |
| 11 | 96    | S     | 1   | 1      |
| 12 | 60    | C     | 4   | 1      |
| 13 | 65    | C     | 4   | 0      |
| 14 | 62    | C     | 4   | 0      |
| 15 | 71    | B     | 3   | 1      |
+----+-------+-------+-----+--------+

I want to devide it in some random no. of sections.

  1. Say 3 SECTIONS SEC A=5, SEC B=5,SEC C=5 students e.g.

A=[SABCS],B=[SABCB],C=[SABCB] //Grades

  1. Say 4 SECTIONS SEC A=4, SEC B=4,SEC C=4, SEC D=3 students e.g.

A=[SABC],B=[SABC],C=[SABC], D=[SBB] //Grades

  1. Say 2 SECTIONS SEC A=8, SEC B=7 students e.g.

A=[SABCSABC],B=[SABCSBB] //Grades

I followed the link got the results but has lots of limitations of balanced distributation.

how can i set and get the required result where section division will be dynamic.

  1. MYSQL will be a preferable.

2.Through java/else coding will be also acceptable.

N.B.:UPDATING for who doesnt get it.

PLEASE see the table and corresponding grades.Then divide the grades(actually students) in each section. Each section should/must contain every grade students. That is why I mensioned BALANCED DISTRIBUTATION.

Joe
  • 479
  • 3
  • 8
  • 31
  • 3
    I dont understand how you want the selection in each of the sections. Can it be random? or do you want some sort of balance?. And if it is random, how does the input table matter, you just need a random set of 4 groups from the unique set of values in the column `grade` right? – Raunak Thomas Feb 20 '18 at 05:02
  • Your question lakes your desired output, and what queries you've tried so far (or any code). However, I'll give you a hint, in MySQL use MOD() to get the reminder, and COUNT(*) to get the number of rows, then use your math skills, such as ( if the count is not divisible by (number of sets) then subtract ( count - the reminder) and use the returned number in your mysql query such as LIMIT number of rows, skipped rows and maybe a Loop to select every group (or even a java loop). – iSR5 Feb 20 '18 at 06:37

2 Answers2

2

The following approach sorts the data by gradeId and fills each section simultaneously

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class SectionDivider {
  public static void main(String[] args) {
    List<Student> students =
        Arrays.asList(
            new Student(1, 95f, "S", 1),
            new Student(2, 95f, "S", 1),
            new Student(3, 93f, "S", 1),
            new Student(4, 75f, "B", 3),
            new Student(5, 74f, "B", 3),
            new Student(6, 83f, "A", 2),
            new Student(7, 83f, "A", 2),
            new Student(8, 83.5f, "A", 2),
            new Student(9, 70f, "B", 3),
            new Student(10, 71f, "B", 3),
            new Student(11, 96f, "S", 1),
            new Student(12, 60f, "C", 4),
            new Student(13, 65f, "C", 4),
            new Student(14, 62f, "C", 4),
            new Student(15, 71f, "B", 3));

    int numberOfSections = 4;
    String[] divided = new String[numberOfSections];
    int divIdx = 0;

    Map<Integer, List<Student>> groupedGrades =
        students
            .stream()
            .sorted((d1, d2) -> d1.gradeId.compareTo(d2.gradeId))
            .collect(Collectors.groupingBy(d -> d.gradeId));

    while (true) {
      boolean allEmpty = true;
      for (Entry<Integer, List<Student>> entry : groupedGrades.entrySet()) {
        List<Student> value = entry.getValue();
        int size = value.size();
        for (int i = 0; i < numberOfSections && i < size; i++) {
          allEmpty = false;
          if (divided[divIdx] == null) {
            divided[divIdx] = "";
          }
          divided[divIdx] = divided[divIdx].concat(value.get(0).grade);
          divIdx = (divIdx + 1) % numberOfSections;
          value.remove(0);
          entry.setValue(value);
        }
      }
      if (allEmpty) {
        break;
      }
    }

    Arrays.stream(divided).forEach(System.out::println);
  }
}

class Student {
  Integer id;
  Float marks;
  String grade;
  Integer gradeId;

  public Student(Integer id, Float marks, String grade, Integer gradeId) {
    super();
    this.id = id;
    this.marks = marks;
    this.grade = grade;
    this.gradeId = gradeId;
  }
}

The output varies with your sample examples, but distributes the data evenly. [You can edit numberOfSections, studentsand try out]

Onkar Kamatkar
  • 212
  • 2
  • 10
1

If I understand correctly, you'd want to add students of all grades, as evenly as possible in each group. In this case I'd do the following:

  1. sort the students by grade
  2. apply the logic from the referred question to build the groups
  3. sort by the temporary column (group) as in the above question.

The above is arguably the simplest implementation. You might want to add a rule where each group's grade is as close as possible to the average, along the lines of this approach.

I'm afraid that for more complex algorithms you'll need to move to a generic language like java/python.

Laur Ivan
  • 4,117
  • 3
  • 38
  • 62
  • thanks Ivan, I have already referred your first link but found some limitation. Mixing with your second link sounds nice. – Joe Feb 21 '18 at 05:01