今日はpaizaの渡されたリストを元に「背の順」に並び替える問題に挑戦!
久しぶりに Map()
を使ったけど、結局不要だったみたい😆
あと、おまけでオブジェクトについて勉強してみた!
問題概要
-
生徒数 N と、各生徒の「身長」と「名前」が渡される
-
身長が高い順に並べ替えて、名前だけを上から出力する
入力例:
3
173 Hashimoto
195 Yamamoto
113 Yoshida
出力例:
Yamamoto
Hashimoto
Yoshida
🔺OK?NG?例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
rl.on('line', (input) => {
lines.push(input);
});
rl.on('close', () => {
const N = Number(lines[0]);
const arrA =lines.splice(1).map(line => line.split(' '));
const height = new Map();
for(let i = 0; i < N; i++){
height.set(arrA[i][0], arrA[i][1]);
}
const order = [...height.keys()].sort((a,b) => b-a);
order.forEach(h => {
console.log(height.get(h));
})
});
一応、paizaのテストケースは全て ✅正解判定 だったけども、
同じ身長の人がいると 後から登録した人に上書きされてしまう!
✅OK例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
rl.on('line', (input) => {
lines.push(input);
});
rl.on('close', () => {
const N = Number(lines[0]);
const arrA =lines.splice(1).map(line => line.split(' '));
const order = arrA.sort((a,b) => b[0] - a[0]);
order.forEach(a => {
console.log(a[1]);
})
});
配列に[身長, 名前]をセットでして、ソート条件で先頭の要素(身長)を降順にすればOK!(b[0] – a[0]
)
🗒️メモ
-
Map
は同じキー(同じ身長)で上書きされるのでNG! -
文字列のままソートすると数値順じゃなく辞書順になる罠あり
-
sort()
で数値ソートする場合は必ずb - a
!(背の高い順)
💡おまけ:オブジェクト
やってることは二次元配列のやり方と同じだけど、Map
と同じで(身長)キーが重複したらアウト❌
でも、触れたことなかったから、そろそろオブジェクトを勉強して試してみる!
✅ オブジェクトの基本構造
const student = {
height: 173,
name: "Hashimoto"
};
ここで student
はオブジェクトで、
height
と name
という キー(プロパティ名) と
それぞれの 値(バリュー) を持っている。
✅ 値を取り出す方法
オブジェクトから値を取り出す方法は主に2つ
1️⃣ ドット記法 .
書き方:
student.height // 173
student.name // "Hashimoto"
- オブジェクト.プロパティ名
2️⃣ ブラケット記法 []
書き方:
student["height"] // 173
student["name"] // "Hashimoto"
-
オブジェクト["プロパティ名"]
-
文字列としてキーを指定する。
✅ いつ [] を使う?
- キー名を変数で動的に指定したいとき
const key = "height";
console.log(student[key]); // 173
- キー名に空白や特殊文字が含まれていて、ドットで書けないとき
const obj = { "my height": 173 };
console.log(obj["my height"]); // OK
// obj.my height ←これはエラー
✅ なぜオブジェクトにまとめると便利か?
例えば:
students.sort((a, b) => b.height - a.height);
-
a
は{ height: 173, name: "Hashimoto" }
-
b
も同じ形
なので a.height
を参照すれば身長、a.name
で名前がすぐ取れる。
配列だけで分けてたら:
[173, "Hashimoto"]
みたいな形だと、どっちがどっちかは インデックス(0番、1番)に依存 するので可読性が落ちる。
🔑 まとめ
-
.
で中身を引き出せる -
[]
は文字列や変数でキーを動的に扱える - オブジェクトにまとめると「セットで管理」できる
- 並び替えしても紐づけが壊れない
- キーは文字列限定(Symbol は例外だけど基本は文字列)
- 同じキーを後から追加すると上書きされる
→ 同じキーで複数の値を同時に保持するのは不可
💡今回の問題でのコード例
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', (input) => {
lines.push(input);
});
rl.on('close', () => {
const N = Number(lines[0]);
//オブジェクト
const students = lines.slice(1).map(line => {
const [height, name] = line.split(' ');
return { height: Number(height), name };
});
students.sort((a, b) => b.height - a.height);
students.forEach(student => console.log(student.name));
});
✅ 何をしているか?分解して解説
const students = lines.slice(1).map(line => {
const [height, name] = line.split(' ');
return { height: Number(height), name };
});
これを分解すると:
1️⃣ lines.slice(1)
→ 1行目の「N」は要らないので、2行目以降を取得。
例:
["173 Hashimoto", "195 Yamamoto", "113 Yoshida"]
2️⃣ .map(...)
→ 各行 "173 Hashimoto"
を split(' ')
で
[ "173", "Hashimoto" ]
にする。
3️⃣ return { height: Number(height), name };
→ 分割代入で height
と name
に分けて、
{ height: 173, name: "Hashimoto" }
のようなオブジェクトを返す。
結果として、students
はこうなる:
[
{ height: 173, name: "Hashimoto" },
{ height: 195, name: "Yamamoto" },
{ height: 113, name: "Yoshida" }
]
✅ なんでオブジェクトにするのか
「身長」と「名前」を一緒に扱いたい から。
- 身長だけだと名前を忘れる
- 名前だけだと身長がわからない
-
Map
にするほど複雑でもない
なので、1つの要素に両方を まとめる箱 として、
{ height, name }
にする。
✅ どう使うのか
1.ソートで便利
students.sort((a, b) => b.height - a.height);
-
a
とb
はオブジェクト{ height, name }
だから -
b.height - a.height
として簡単に比較できる
2.出力で便利
students.forEach(student => console.log(student.name));
-
student
は{ height, name }
-
student.name
で名前だけ取れる(student
はソート済み)