paizaラーニング レベルアップ問題集 ソートメニュー応用編 JavaScript タプルソート

# paizaラーニング レベルアップ問題集 ソートメニュー応用編 JavaScript タプルソート
タプルソート (paizaランク B 相当)

https://paiza.jp/works/mondai/sort_advanced/sort_advanced__problems_speedup_step5


解いてみました。
## 解答コード例（JavaScript） C++ の場合(1)の模範解答参考
ソート前に、優先順位の高い順にしておきます。この問題では、
[ k 列目, 1 列目, 2 列目, ..., k - 1 列目, k + 1 列目, ..., m 列目 ] 
の順にしてから、優先順位の低い末尾からソートを実行し、その後、元に戻します。
```javascript:JavaScript
  const fs = require("fs");
  const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
  const lines = input.split("\n");
  //n 行 m 列 の表 a , k 列目が昇順
  const [n, m, _] = lines[0].split(" ").map(Number);
  let [_, _, k] = lines[0].split(" ").map(Number);
  k--;//表aのインデックスで扱うので-1する

  //入力cin
  const cin = lines.slice(1).map(line => line.split(" ").map(Number));
  //表 a 
  const a = Array(n).fill(0).map(v => v = Array(m));
  // k 番目の値を配列の先頭に入れる
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
      if (j === k) {
        a[i][0] = cin[i][j];
      } else if (j < k) {
        a[i][j + 1] = cin[i][j];
      } else {
        a[i][j] = cin[i][j];
      }
    }
  }

  //優先順位の低い末尾の列からソート実行
  for (let i = m - 1; i >= 0; i--) {
    a.sort((a, b) => a[i] - b[i]);
  }

  
  //戻し先の配列を作る
  const sorted = Array(n).fill(0).map(row => row = []);
  //先頭に入れた k 番目の値を元の位置に戻す
  for (let i = 0; i < n; i++) {
    //kの前
    for (let j = 1; j < k + 1; j++) {
      sorted[i].push(a[i][j]);
    }
    //kを元に戻す
    sorted[i].push(a[i][0]);
    //kの後
    for (let j = k + 1; j < m; j++) {
      sorted[i].push(a[i][j]);
    }
  }
  
  //出力
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
      if (j === 0) {
        process.stdout.write(String(sorted[i][j]));
      } else {
        process.stdout.write(" " + String(sorted[i][j]));
      }
    }
    process.stdout.write("\n");
  }
```
表aを作るところは、メソッドを使って以下のようにも書けます。
```javascript:JavaScript
  //表 a 
  const a = [];
  // k 番目の値を配列の先頭に入れる
  for (let i = 0; i < n; i++) {
    const a_i = lines[i + 1].split(" ").map(Number);//表aのi行目
    const head = a_i.splice(k, 1);//k番目を抜く
    a_i.unshift(...head);//抜いたk番目を先頭につける
    a.push(a_i);//表aのi行目にpush
  }
```
最後の出力のところは、以下のように１行でも書けます。
```javascript:JavaScript
  //出力
  console.log(a.map(row => row.join(" ")).join("\n"));
```
## 解答コード例（JavaScript） C++ の場合(2)の模範解答参考
sort関数の中で、優先順位にしたがって、ifで場合分けをしても解くことができます。
ifは先に来る方が優先されます。
k 番目の値が等しくない場合はすぐに比較が完了します。k 番目の要素が最優先だからです。
k 番目の値が等しい場合は k 番目以外の値を先頭から順に見ていきます。

```javascript:JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//n 行 m 列 の表 a , k 列目が昇順
let [n, m, k] = lines[0].split(" ").map(Number);
k--;//表aのインデックスで扱うので-1する

//表 a
const a = lines.slice(1).map(line => line.split(" ").map(Number));
 
//ソート実行
a.sort((a_l, a_r) => {
  //ifは優先順位が高い方が先
  if (a_l[k] !== a_r[k]) { // k 番目の要素の値が異なるとき 
    return a_l[k] - a_r[k]; //k 列目を昇順に
  } else { //k 番目の要素の値が等しかったら、
    for (let i = 0; i < a_l.length; i++) { //i番目の要素の値を調べる
      if (i === k) { //k 番目の要素はスキップ
        continue;
      }
      if (a_l[i] !== a_r[i]) { // i番目の要素の値が異なるとき
        return a_l[i] - a_r[i]; // i 列目の値を昇順に
      }
    }
    // すべての要素の値が等しいとき
    return 0;
  }  
});

//出力
for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
      if (j === 0) {
        process.stdout.write(String(a[i][j]));
      } else {
        process.stdout.write(" " + String(a[i][j]));
      }
    }
    process.stdout.write("\n");
}
```

こちらも最後の出力のところは、以下のように１行でも書けます。
```javascript:JavaScript
  //出力
  console.log(a.map(row => row.join(" ")).join("\n"));
```