{ }codelper
推导式分组P0123

反转选课名单

给出 n 行,每行写着一名学生所选的课程。
不用循环,而用集合推导式和字典推导式构造并输出以下内容。
第一行是 n,接下来 n 行形如 "名字 课程 课程 ..."。
有的行没有任何课程。
同一名学生可能出现在多行中,该学生的课程是这些行合并起来的结果。
同一行中重复出现的课程只算一次。
1) 输出不同学生的人数 S,接着按名字顺序输出 S 行 "名字 k 课程1 ...
课程k"。
k 是该学生所选不同课程的数目,课程排序后写出。
没有课程时为 "名字 0"。
2) 输出不同课程的个数 C,接着按课程顺序输出 C 行 "课程 m 名字1 ...
名字m"。
m 是选这门课的学生人数,名字排序后写出。
3) 把只有一名学生的课程排序后,在一行中用空格分隔输出。
若没有这样的课程,输出 -。
所有排序都按字符串的编码顺序(Python 字符串比较)进行。

输入
1 ≤ n ≤ 1000。
名字为 1 到 8 个小写英文字母。
课程为 2 到 6 个大写英文字母和数字,每行 0 到 10 个,不同课程不超过 200 个。
输出
1) S + 1 行,2) C + 1 行,3) 一行
样例 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
样例 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
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 1 种语言题解

本题只接受 Python,因为列表、集合、字典推导式是 Python 的语法。
其他语言用循环,或 map、filter(JS)、流的 groupingBy(Java)、LINQ 的 GroupBy、ToDictionary(C#)来做同样的事。
在 Craykon 中则用 字典()、遍历 循环和 包含 来做。
字典推导式 {键: 值 for ...} 就是集合推导式的花括号再加一个 :,在值的位置放一个集合推导式,"学生 → 课程集合" 就成了一行。
第一个单词和其余部分用星号解包分开:for name, *courses in ...。
三个陷阱:① 像 {name: set(courses) for name, courses in rows} 那样每行建一个键,同一个键再次出现时,最后的值会不报错地覆盖前面的值。
应先把不同的学生收集成集合,再在值的推导式中合并该学生的所有行。
② 用列表推导式 [...] 构造值,同一行中重复的课程会被存两次,k 变大。
去重要用集合推导式 {...}。
③ dict.fromkeys(课程, []) 只创建一个空列表,并把同一个列表放到每个键下。
所以加到一门课的学生会出现在所有课程中。
每个键需要新值时,要用 {c: [] for c in ...} 这样的推导式。
集合没有顺序,而字符串的哈希值每次运行都不同,所以遍历集合构造的字典在每次运行时顺序也会变。
输出前要用 sorted 排序。

Pythonmain.py · 20 行
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 "-")