Отсортировать информацию по правилу. Java

Отсортировать информацию по правилу: теме теста один раз, далее фамилия тестируемого и результат тестирования.
Ввод производится в список
В формате Фамилия тема_теста/оценка
Пример:
Ввод:
Иванов массивы/5.00,списки/3.49
Сидоров массивы/4.50,классы/5.00
Вывод:
массивы
Иванов 5.00
Сидоров 4.50
списки
Иванов 3.49
классы
Сидоров 5.00
Суть вопроса: Как это можно реализовать что бы тема теста не повторялась Код который я набросал

Scanner in= new Scanner(System.in);
    List result = new ArrayList();
    List nameOfTests = new ArrayList();
    System.out.println("Начните вводить Фамилию + тему теста +оценку)(В формате Фамилия тема_теста/оценка). Окончанием служит 0 ");
    String str = in.nextLine();
    while(!(str.equals("0"))) {
        result.add(str);
        str = in.nextLine();
    }
    
    
    for (int i = 0;i<result.size();i++){
                str = (String) result.get(i);
                String[] str1 = str.split(" ");
                String[] str2 = str1[1].split(",");
                for(int j = 0;j<str2.length;j++){
                    String[] str3 = str2[j].split("/");
                    nameOfTests.add(str3[0]);
                    
                }
            }
            Set<String> set = new HashSet<>(nameOfTests);
            nameOfTests.clear();
            nameOfTests.addAll(set);
            for(int i = 0;i<result.size();i++){
                str = (String) result.get(i);
                String[] str1 = str.split(" ");
                String[] str2 = str1[1].split(",");
                String newstr = (String) nameOfTests.get(i);
                System.out.println(newstr);
                for(int j = 0;j<str2.length;j++){
                    String[] str3 = str2[j].split("/");
                    str = (String) result.get(i);
                    String[] str4 = str.split(" ");
                    String[] str5 = str4[1].split(",");
                    for (int raw = 0;raw<str5.length;raw++){
                        String[] str6 = str5[raw].split("/");
                        if(newstr.equals(str6[0])){
                            System.out.println(str4[0]);
                            System.out.println(str6[1]);
                        }
                        
                    }
            }
            }

Получается вот так вот


Ответы (3 шт):

Автор решения: had0uken

Воспользуйтесь MAP. Map хранит только уникальные значения ключей. В моем МАР ключ - это предмет, а values - это все фамилии и их оценки по этому предмету. Код:

public class Task3 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        Map<String, String> map = new HashMap<>(); // предмет, фамилия и оценка
        System.out.println("Начните вводить Фамилию + тему теста +оценку)(В формате Фамилия тема_теста/оценка). Окончанием служит 0 ");
        //Регулярное выражение подгоните под свои вводимые данные
        //Мое подходит под те, которое вы дали в вопросе
        Pattern pattern = Pattern.compile("(\\W+)(\\s)(\\W+)(/)(\\d.\\d\\d)(,)()(\\W+)(/)(\\d.\\d\\d)");
        String str = in.nextLine();
        while (!(str.equals("0"))) {
            Matcher matcher = pattern.matcher(str);
            //парсим введеное значение, находим Фамилию, предмет№1, предмет№2,
            //оценку №1, оценку№2
            //Проверяем есть ли в МАР уже такой предмет,
            //если нет, то добавляем в МАР новый ключ - предмет и в value добавляем
            //фамилию и оценку (ветка else).
            //Если уже есть такой предмет в МAP, то делаем тоже самое, только старое значение
            //values конкатенируем с новым значением

            if (map.containsKey(matcher.replaceAll("$3")))
                map.put(matcher.replaceAll("$3"), map.get(matcher.replaceAll("$3")) + "\n" +
                        matcher.replaceAll("$1\n$5"));
            else
                map.put(matcher.replaceAll("$3"), matcher.replaceAll("$1\n$5"));

            if (map.containsKey(matcher.replaceAll("$8")))
                map.put(matcher.replaceAll("$8"), map.get(matcher.replaceAll("$8")) + "\n" +
                        matcher.replaceAll("$1\n$10"));
            else
                map.put(matcher.replaceAll("$8"), matcher.replaceAll("$1\n$10"));
            str = in.nextLine();
        }
        //Выводим результат
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "\n" + entry.getValue());
        }
    }
}

Выход:

Начните вводить Фамилию + тему теста +оценку)(В формате Фамилия тема_теста/оценка). Окончанием служит 0 
Иванов массивы/5.00,списки/3.49
Сидоров массивы/4.50,классы/5.00
0
массивы
Иванов
5.00
Сидоров
4.50
списки
Иванов
3.49
классы
Сидоров
5.00
→ Ссылка
Автор решения: had0uken

Если вам принципиально воспользоваться списком, а не МАР, то придется создавать два списка и использовать вложенный цикл. В списке subjects хранятся уникальные названия предметов, в списке examtList хранятся объекты класса Exam, содержащего информацию о каждом экзамене. Код ниже:

    public class Test4 {
    static List<Exam> examList = new ArrayList<>();
    static List<String> subjects = new ArrayList<>();
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("Начните вводить Фамилию + тему теста +оценку)(В формате Фамилия тема_теста/оценка). Окончанием служит 0 ");
        String str = in.nextLine();
        while (!(str.equals("0"))) {
            stringParser(str);
            str = in.nextLine();
        }
        //Вывод результата на экран
        for (int i = 0; i < subjects.size(); i++) {
            System.out.println(subjects.get(i));
            for (int j = 0; j < examList.size(); j++)
                if (examList.get(j).getSubjectName().equals(subjects.get(i))) {
                    System.out.println(examList.get(j).getName());
                    System.out.println(examList.get(j).getGrade());
                }
        }
    }
    static void stringParser(String str){
        String name = str.substring(0, str.indexOf(' '));
        //Из первой части строчки вытащили имя студента, теперь вторую часть превращаем в массив
        //для этого разделяем строчку по символу "/", предварительно заменив все "," на "/"
        String [] grades = str.substring(str.indexOf(' ')+1,str.length()).replaceAll(",","/").split("/");

        for(int i=0;i<grades.length;i+=2)
        {
            if(!subjects.contains(grades[i]))
                subjects.add(grades[i]);

            examList.add(new Exam(grades[i],name,grades[i+1]));
        }
     }
}

class Exam {
    private String subjectName;
    private String name;
    private String grade;

    public Exam(String subjectName, String name, String grade) {
        this.subjectName = subjectName;
        this.name = name;
        this.grade = grade;
    }

    public String getSubjectName() {
        return subjectName;
    }

    public String getName() {
        return name;
    }

    public String getGrade() {
        return grade;
    }
}

Выход:

Начните вводить Фамилию + тему теста +оценку)(В формате Фамилия тема_теста/оценка). Окончанием служит 0 
Иванов массивы/5.00,списки/3.49
Сидоров массивы/4.50,классы/5.00
0
массивы
Иванов
5.00
Сидоров
4.50
списки
Иванов
3.49
классы
Сидоров
5.00

Process finished with exit code 0
→ Ссылка
Автор решения: Tufuteca

Ответ нашёл сам который меня устроил.

Scanner in= new Scanner(System.in);
    List result = new ArrayList();
    List nameOfTests = new ArrayList();
    System.out.println("Начните вводить Фамилию + тему теста/оценка (темы через запятую). Окончанием служит 0 ");
    String str = in.nextLine();
    while(!(str.equals("0"))) {
        result.add(str);
        str = in.nextLine();
    }
    for (int i = 0;i<result.size();i++){
                str = (String) result.get(i);
                String[] str1 = str.split(" ");
                String[] str2 = str1[1].split(",");
                for(int j = 0;j<str2.length;j++){
                    String[] str3 = str2[j].split("/");
                    nameOfTests.add(str3[0]);
                    
                }
            }
            Set<String> set = new HashSet<>(nameOfTests);
            nameOfTests.clear();
            nameOfTests.addAll(set);
            Collections.sort(result);
            for (int j = 0;j<nameOfTests.size();j++){
                System.out.println();
                    String str1 = (String) nameOfTests.get(j);
                    System.out.println(nameOfTests.get(j));
            for(int i = 0 ;i<result.size();i++){
                str = (String) result.get(i);
                if(str.contains(str1)){
                    String[] str2 = str.split(" ");
                    String[] str3 = str2[1].split(",");
                    for(int raw=0;raw<str3.length;raw++){
                        String[] str4 = str3[raw].split("/");
                        if(str4[0].equals(str1)){
                            System.out.println(str2[0]+" "+str4[1]);
                    }
                }
            }
}

}

→ Ссылка