第102回【JavaScript】辞書データの順序、辞書

現在取り組んでいるのは、paiza ラーニング問題集「Cランクレベルアップメニュー」になります。

はじめに

猫とキャンプと野球観戦と AWS が大好きな旦那、LeoSaki です。モフモフしたい。

JavaScript をゼロから勉強してみよう、のコーナー 102 回目です。

前回新しく Map を身に付けてから、過去に書いた JavaScript のコードを見直して、ちょっと書き直してみて、なるほど、便利だ、ということに気が付きました。こういう学びが学習を続けていくうえでの活力です。

それでは、今日も頑張ってみようと思います。

辞書データの順序 (paizaランク C 相当)

n 人の人の名前 s_1, …, s_n が与えられたのち、 m 回の「攻撃」に関する情報が与えられます。各行は “p_i a_i” というフォーマットで与えられ、 p_i はダメージを受けた人の名前 (s_1, …, s_n のいずれか) 、 a_i は p_i が受けたダメージ数を表す数です。なお、一度もダメージを受けていない人の合計ダメージは 0 とします。

それぞれの人が受けた合計ダメージを、人の名前のアルファベットの辞書順に出力してください。


入力される値

n
s_1
...
s_n
m
p_1 a_1
...
p_m a_m

1 行目には正整数 n が与えられ、 2 行目から (n + 1) 行目には人の名前 s_1, …, s_n が改行区切りで与えられます。 (n + 2) 行目には正整数 m が与えられ、 (n + 3) 行目から (n + m + 2) 行目には人の名前 p_i (s_1, …, s_n のいずれか) とその人が受けたダメージ a_i が “p_i a_i" という半角スペース区切りのフォーマットで m 行与えられます。

入力値最終行の末尾に改行が1つ入ります。


期待する出力

それぞれの人が受けたダメージを、人の名前のアルファベットの辞書順に n 行出力してください(出力するのはダメージだけです)。

また、末尾に改行を入れ、余計な文字、空行を含んではいけません。


すべてのテストケースにおいて、以下の条件をみたします。

・1 ≤ n , a_i ≤ 50 (1 ≤ i ≤ n)
・各 s_i (1 ≤ i ≤ n) はアルファベット大文字からなる長さ 1 以上 50 以下の文字列で、互いに全て異なる


入力例

2
MIDORIKAWA
KIRISHIMA
2
KIRISHIMA 1
KIRISHIMA 2

出力例

3
0

ロープレみたいで面白い。

JavaScript
process.stdin.resume();
process.stdin.setEncoding('utf8');

var lines = [];
var reader = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
});
reader.on('line', (line) => {
  lines.push(line);
});
reader.on('close', () => {
  const n = Number(lines[0]);
  const players = new Map();
  for (let i = 1; i <= n; i++) {
      players.set(lines[i],0);
  }
  const m = Number(lines[n + 1]);
  for (let i = n + 2; i <= n + m + 1; i++) {
      const [p,a] = lines[i].split(/\s/);
      players.set(p,players.get(p) + Number(a));
  }
  const newPlayers = new Map([...players].sort());
  newPlayers.forEach((v) => console.log(v));
});
Python
N = int(input())
dic = { input():0 for _ in range(N) }
M = int(input())
for _ in range(M):
    p,a = input().split()
    dic[p] += int(a)
dic = sorted(dic.items())
for k,v in dic:
    print(v)

辞書 (paizaランク C 相当)

p 人のグループ A , q 人のグループ B , r 人のグループ C があります。各グループのメンバーにはそれぞれ番号がつけられており、 A グループの i 番目の人は B グループの j 番目の人に仕事を任せ、 B グループの j 番目の人は与えられた仕事を C グループの k 番目の人に任せます。すると結局、 A グループの i 番目の人の仕事をするのは C グループの k 番目の人だということになります。

パイザ君は A グループの各人の仕事を結局 C グループの誰が行うことになるのか知りたがっています。 A グループの人のそれぞれが最終的に C グループの誰に仕事を頼むことになるのかを、 A グループの人の番号が小さい順に p 行出力してください。


入力される値

p q r
i_1 j_1
...
i_p j_p
j'_1 k_1
...
j'_q k_q

1 行目には A グループ、 B グループ、 C グループのそれぞれの人数 p , q , r が半角スペース区切りで与えられます。
2 行目から (p + 1) 行目までは A グループの人の番号とその人が仕事を頼む B グループの人の番号 i_a, j_a (1 ≤ a ≤ p) が半角スペース区切りで、 (p + 2) 行目から (p + q + 2) 行目までは B グループの人の番号とその人が仕事を頼む C グループの人の番号 j’_b , k_b (1 ≤ b ≤ q) が半角スペース区切りで与えられます。

入力値最終行の末尾に改行が1つ入ります。


期待する出力

A グループの i_c 番目の人が C グループの k_c 番目の人に仕事を頼むとしたとき (1 ≤ c ≤ p) 、各 i_c, k_c をそれぞれ半角スペース区切りで、 i_c が小さい順に p 行出力してください。

また、末尾に改行を入れ、余計な文字、空行を含んではいけません。


すべてのテストケースにおいて、以下の条件をみたします。

・1 ≤ p , q , r ≤ 50
・1 ≤ i_a ≤ p , 1 ≤ j_a , j’_b ≤ q , 1 ≤ k_b ≤ r (1 ≤ a ≤ p , 1 ≤ b ≤ q)
・各 i_a は全て異なる
・各 j’_b は全て異なる

A グループから仕事を頼まれた B グループの人は必ずその仕事を C グループの誰かに頼みます。 B グループに関する入力には「余計な」ものも含まれます。すなわち、 A グループの誰からも仕事を頼まれていない B グループの人に関して、その人が C グループの誰に仕事を頼むかについての情報が与えられることもあります。


入力例

2 2 2
2 1
1 2
1 1
2 2

出力例

1 2
2 1

孫請け問題。横行しているのだろうけれども。

JavaScript
process.stdin.resume();
process.stdin.setEncoding('utf8');

var lines = [];
var reader = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
});
reader.on('line', (line) => {
  lines.push(line);
});
reader.on('close', () => {
  const [p,q,r] = lines[0].split(/\s/).map(Number);
  const A = [];
  const ab = new Map();
  const bc = new Map();
  for (let i = 1; i <= p; i++) {
      const [a,b] = lines[i].split(/\s/).map(Number);
      ab.set(a,b);
      A.push(a);
  }
  for (let i = p + 1; i <= p + q; i++) {
      const [b,c] = lines[i].split(/\s/).map(Number);
      bc.set(b,c);
  }
  A.sort((first,second) => first - second);
  for (const a of A) {
      console.log(a,bc.get(ab.get(a)));
  } 
});
Python
p,q,r = map(int,input().split())
dic_ab = {}
dic_ac = {}
for _ in range(p):
    a,b = map(int,input().split())
    dic_ab[b] = a
for _ in range(q):
    b,c = map(int,input().split())
    if b in dic_ab:
        dic_ac[dic_ab[b]] = c
dic_ac = sorted(dic_ac.items())
for k,v in dic_ac:
    print(k,v)

最後に

なかなか複雑だけれども、ゆっくり考えていけば難しくなかったです。Map はとても使い勝手が良いです。いきなりファンになりました。しかし、並べ替えとか、ちょっとコツがいるなぁと思いました。

今回は、別の配列を用意して sort をしましたけれど、スプレッド構文を使って上手に書けば、もっと綺麗になるかも、とか。もっと学習する必要がありそうです。

引き続き、よろしくお願いいたします!

Python の第102回はこちら