1~100までの整数が奇数かどうかを判定するプログラム.R

by
カテゴリ:

【ゆる募】1~100までの整数が奇数かどうかを判定するプログラム大喜利を開催します☺ 言語不問✨ https://x.com/arith_rose/status/1899300131658510802

とのことで、Rで書いてみましょう。模範解答……?ナニソレオイシイノ?

まずは解答例に近い感じで!

matchがないならswitchすればいいじゃない!

解答例はPythonでmatch文を使ってますが、Rで近しいswitch関数を使うとこんな感じでしょうか。冗長さもさることながら、Rのswitch関数は文字列一致判定をすること、ベクトル化されていないことなど、イマイチ感爆発でステキです!

is_odd <- function(x) {
  switch(as.character(x),
    "1" = TRUE,
    "3" = TRUE,
    "5" = TRUE,
    "7" = TRUE,
    "9" = TRUE,
    "11" = TRUE,
    "13" = TRUE,
    "15" = TRUE,
    "17" = TRUE,
    "19" = TRUE,
    "21" = TRUE,
    "23" = TRUE,
    "25" = TRUE,
    "27" = TRUE,
    "29" = TRUE,
    "31" = TRUE,
    "33" = TRUE,
    "35" = TRUE,
    "37" = TRUE,
    "39" = TRUE,
    "41" = TRUE,
    "43" = TRUE,
    "45" = TRUE,
    "47" = TRUE,
    "49" = TRUE,
    "51" = TRUE,
    "53" = TRUE,
    "55" = TRUE,
    "57" = TRUE,
    "59" = TRUE,
    "61" = TRUE,
    "63" = TRUE,
    "65" = TRUE,
    "67" = TRUE,
    "69" = TRUE,
    "71" = TRUE,
    "73" = TRUE,
    "75" = TRUE,
    "77" = TRUE,
    "79" = TRUE,
    "81" = TRUE,
    "83" = TRUE,
    "85" = TRUE,
    "87" = TRUE,
    "89" = TRUE,
    "91" = TRUE,
    "93" = TRUE,
    "95" = TRUE,
    "97" = TRUE,
    "99" = TRUE,
    FALSE
  )
}
is_odd(1)
#> [1] TRUE
is_odd(2)
#> [1] FALSE

ベクトルの要素を取り出すと簡単にcaseっぽいことできるんだぜ?

これならベクトル化もしてるしなと、Rチョトワカル風を漂わせていていいですね。 100より大きな数値を与えるとNAを返すのでいけてる実装かも……?と思いきや、is_odd(-1)is_odd(1.1)するとたいへんにバグりちらかしております。

is_odd <- function(x) {
  yes <- c(
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
  )
  yes[x]
}
is_odd(1:10)
#>  [1]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
is_odd(101)
#> [1] NA
is_odd(1.1)
#> [1] TRUE
is_odd(-1) # 長さ99のベクトルになる
#>  [1] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [13] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [25] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [37] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [49] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [61] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [73] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [85] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
#> [97] FALSE  TRUE FALSE

もう少し短かく書くなら、repを使うといいでしょう。

is_odd <- function(x) {
  rep(c(TRUE, FALSE), 50)[x]
}

Rらしく書いてみよう

奇数の集合のいずれかに一致するか見ればいいよね!

ここらで解答例から離れて遊んでみましょう。

1:100までの整数を2行に並べたら、1行目は奇数になるので、それと一致するかどうかを見ればいいですね。よく考えているようで、anyを使っているせいで、xに長さ1以外のベクトルを使うとバグります。

is_odd <- function(x) {
  any(x == matrix(1:100, nrow = 2)[1, ])
}
is_odd(1)
#> [1] TRUE
is_odd(c(1, 2))
#> [1] TRUE

奇数の集合に含まれるか見ればいいよね!

さっきよりもスマート。 seqを使うことで、余計なデータを発生させず、%in%を使うことでxに長さ1以外のベクトルを使っても大丈夫です。

is_odd <- function(x) {
  return(x %in% seq(1, 100, by = 2))
}
is_odd(1)
#> [1] TRUE
is_odd(1:10)
#>  [1]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE

問題文をよく読もう!

真っ当な実装!だけど忠実すぎるぜ!

奇数かどうかの判定なら、2で割った余りが1かどうか見ればOKですね。真っ当な実装です。

ところが、問題文に従って、xの要素が1つでも1~100の整数という条件に従わない時にエラーを出しています。忠実すぎて余計なお世話ですね。 is_oddという関数名としては余計なお世話ですが、実際のプロダクトでは要件次第で入りうるバリデーションでもあります。

is_oidd <- function(x) {
  if (any(x < 1 | x > 100 | floor(x) != x)) {
    stop("1~100の整数を入力してください")
  }
  return(x %% 2 == 1)
}
is_odd(1)
#> [1] TRUE
is_odd(c(-1, 1))
#> [1] FALSE  TRUE
is_odd(c(1, 101))
#> [1]  TRUE FALSE
is_odd(0.1)
#> [1] FALSE

判定しろとは言うが、形式は指定してないよな!

ひたすら文字列をprintしてお知らせします。使いにくいわ!

is_odd <- function(x) {
  for (ok in x %% 2 == 1) {
    if (ok) {
      print("そうだよ")
    } else {
      print("ちがうよ")
    }
  }
}
is_odd(1:10)
#> [1] "そうだよ"
#> [1] "ちがうよ"
#> [1] "そうだよ"
#> [1] "ちがうよ"
#> [1] "そうだよ"
#> [1] "ちがうよ"
#> [1] "そうだよ"
#> [1] "ちがうよ"
#> [1] "そうだよ"
#> [1] "ちがうよ"

ENJOY!!

たまにこうして遊ぶと、Rの楽しさを再認識しますね!

たいへんにoddなコードをたくさん書けて楽しかったです!

ふざけてはいるのですが、テストケースの考えかたや、要件の整理など、プログラミングに重要な要素がいっぱい詰まった良問と思いました!