{ }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 "-")