{ }codelper
comprehensionsgroupingP0123

Flip the class roster

You are given n lines, each listing the courses a student takes.
Build and print the following with set and dict comprehensions instead of loops. The first line has n, and the next n lines have "name course course ...".
Some lines have no courses. The same student may appear on several lines, and that student's courses are all of those lines combined.
A course repeated within a line counts once. 1) Print the number of different students S, then S lines "name k course1 ...
coursek" in name order.
k is the number of different courses the student takes, and the courses are written sorted.
A student with no courses gives "name 0". 2) Print the number of different courses C, then C lines "course m name1 ...
namem" in course order.
m is the number of students taking the course, and the names are written sorted. 3) Print, sorted on one line separated by spaces, the courses that have exactly one student.
If there is no such course, print -. All sorting is by the code order of strings (Python string comparison).

Input
1 ≤ n ≤ 1000.
Names are 1 to 8 lowercase English letters.
Courses are 2 to 6 uppercase English letters and digits, 0 to 10 per line, and there are at most 200 different courses.
Output
1) S + 1 lines, 2) C + 1 lines, 3) one line
Example 1 · stdin
4
kim ART MATH
lee MATH
kim BIO
kim
stdout
2
kim 3 ART BIO MATH
lee 1 MATH
3
ART 1 kim
BIO 1 kim
MATH 2 kim lee
ART BIO
Example 2 · stdin
3
mia CS CS
joy CS ART ART
zoe
stdout
3
joy 2 ART CS
mia 1 CS
zoe 0
2
ART 1 joy
CS 2 joy mia
ART
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 1 languages

This problem takes only Python, because list, set and dict comprehensions are Python syntax.
Other languages do the same with loops, or map/filter (JS), stream groupingBy (Java), LINQ GroupBy/ToDictionary (C#).
In Craykon you would use Dict() with a foreach loop and Contains.
A dict comprehension {key: value for ...} is the set-comprehension braces plus a :, and putting a set comprehension in the value turns "student → set of courses" into one line.
Split the first word from the rest with star unpacking: for name, *courses in ....
Three traps: (1) making a key per line, as in {name: set(courses) for name, courses in rows}, silently lets the last value overwrite the earlier one when a key comes again.
Collect the different students into a set first, and merge all of that student's lines in the value comprehension.
(2) Building the value with a list comprehension [...] stores a course repeated on a line twice, so k grows.
Removing duplicates is what the set comprehension {...} does.
(3) dict.fromkeys(courses, []) makes only one empty list and puts that same list under every key, so a student added to one course shows up in every course.
When each key needs a fresh value, use a comprehension like {c: [] for c in ...}.
Sets have no order, and string hashes change from run to run, so a dict built by iterating a set changes order between runs too.
Sort with sorted before printing.

Pythonmain.py · 20 lines
n = int(input())# 줄마다 (이름, [과목...]) — 별표 풀어 넣기로 첫 낱말과 나머지를 나눈다rows = [(name, courses) for name, *courses in (input().split() for _ in range(n))] # 학생 → 과목 집합. 같은 학생이 여러 줄에 나오면 모두 합친다students = {name for name, _ in rows}taken = {s: {c for name, courses in rows if name == s for c in courses} for s in students} # 과목 → 학생 목록(뒤집기)all_courses = {c for courses in taken.values() for c in courses}roster = {c: sorted(s for s, courses in taken.items() if c in courses) for c in all_courses} print(len(taken))for s in sorted(taken):    print(s, len(taken[s]), *sorted(taken[s]))print(len(roster))for c in sorted(roster):    print(c, len(roster[c]), *roster[c])lonely = sorted(c for c, names in roster.items() if len(names) == 1)print(" ".join(lonely) if lonely else "-")