6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年5月21日 番外編アルゴ式

今回の問題

  • 配列の要素と右隣の数字を比較して右隣が大きいケースの回数をカウントするという内容です。

解答

yano's answer

  • Array.prototype.reduce()を使用しました。
  • countを出す・配列のindexを使って操作する点などでreduceが妥当と判断しました。
//(入力受け取り 省略)
type CountUpNumberInArray = {
  (numArray: number[]): number
}

const countUpNumberInArray: CountUpNumberInArray = (numArray) => 
  numArray.reduce((accumulator, currentValue, index, array) => {
    return array[index] < array[index + 1] ? accumulator += 1 : accumulator += 0
  }, 0);

console.log(countUpNumberInArray(a));
  • 関数式の後にreturnを書いた方がわかりやすいかもしれません。
  • reduceの第二引数は使用しないため、アンダースコアで省略した方がいいです。

修正

const countUpNumberInArray: CountUpNumberInArray = (numArray) => {
  return numArray.reduce((accumulator, _, index, array) => {
    return array[index] < array[index + 1] ? accumulator += 1 : accumulator += 0
  }, 0);
}
  • 命名ももう少し拘れると良さそうです。
Rubyでやってみる
  • for in文パターン
n = gets.to_i
a = gets.split.map(&:to_i)

count = 0

for i in 0..n do
  count += 1 if a[i].to_i < a[i + 1].to_i
end

puts count
n = gets.to_i
a = gets.split.map(&:to_i)

count = 0

a.each_with_index do |value, index|
  count += 1 if a[index] < a[index +1].to_i
  if index == a.size - 1
    puts count
  end
end

yuki's answer

  • 素早く命名するのが苦手だと感じました。今後、改善していきます。(現時点の命名も本当に分かりやすいか疑問)
  • reduceを使えば、配列の2つの要素を比べられるので、reduceを使えば良かったです。関数型プログラミングをなるべく自分のコードに取り入れたいと思いました。
import * as fs from 'fs'
const input       = fs.readFileSync("/dev/stdin", "utf8")
const [nv, alist] = input.split("\n")

const [n, ..._]  = nv.split(" ").map(Number)
const list        = alist.split(" ").map(Number)

const countRightThanLeft = (list: number[]): number => {
  let count = 0;
  for (let i = 1; i < list.length; i++) {
    if (list[i-1] < list[i]) {
      count++;
    }
  }
  return count;
}

console.log(countRightThanLeft(list));

yui's answer

import * as fs from 'fs'
const input       = fs.readFileSync("/dev/stdin", "utf8")
const [nv, alist] = input.split("\n")

const [n,v,..._]  = nv.split(" ").map(Number)
const list        = alist.split(" ").map(Number)

type ArrayType = {
    (previousValue: number, currentValue: number, currentIndex: number, array: number[]): number;
}

const reducer: ArrayType = (previousValue, _, currentIndex, array) => {
    const count =  (array[currentIndex] < array[currentIndex + 1]) ? 1 : 0;
    const returnNumber = previousValue + count;
    return returnNumber;
}

console.log(list.reduce(reducer, 0));
  • 今回は、2つの要素の値を比較したいのでreduce()を使いました。
  • reduceメソッドは、配列のそれぞれの要素に対して、順番通りに、コールバック関数を呼び出します。コールバック関数の引数には、累積値, 要素, インデックス, 配列を渡すことが出来ます。配列のすべての要素に対してコールバック関数を実行した結果が戻り値となります。

  • 最初、変数にアノテーションを記述していましたが、型推論を利用するように変更しました。

    • プリミティブ型の値を使うときは、アノテーションを書かずに型推論を使う方が良いです。なぜなら、間違えて型定義してしまうことを防ぐことができるからです。
    • 対して、オブジェクトや関数の引数などはアノテーションを書く方がいいです。オブジェクトを変数に入れた時、プロパティにどんな値が入っているかに関わらず単なるobject型型推論されてしまうからです。
  • 関数の引数として、アンダーバー_が使われている記述があります。これは、使われない引数であることを明示しています。使われない値であるが、単純に引数として書く必要があるため、アンダーバーを使用しています。

アンダーバーのみの変数の意味

参考

アルゴ式