Codewarsで欲を満たす

# はじめに

RUNTEQの中間試験が楽しく、久しぶりにCodewarsをやりたくなったのでやっていきます。

どの言語でやろうかな・・・
JSはホームグラウンド。楽しくできるはず。
Rubyはちょうどやったところ。もういっちょやるのはあり。
Haskellも中間試験やりながらよぎったんだよな・・・きれいな再帰を書きたい・・・

# やってみた問題（JS）

今回はJS 6kyuの問題を解きました。

https://www.codewars.com/kata/56a5d994ac971f1ac500003e/train/javascript

> You are given an array(list) `strarr` of strings and an integer `k`. Your task is to return the **first** longest string consisting of k **consecutive** strings taken in the array.
> 
> #### Examples:
> 
> ```
> strarr = ["tree", "foling", "trashy", "blue", "abcdef", "uvwxyz"], k = 2
> 
> Concatenate the consecutive strings of strarr by 2, we get:
> 
> treefoling   (length 10)  concatenation of strarr[0] and strarr[1]
> folingtrashy ("      12)  concatenation of strarr[1] and strarr[2]
> trashyblue   ("      10)  concatenation of strarr[2] and strarr[3]
> blueabcdef   ("      10)  concatenation of strarr[3] and strarr[4]
> abcdefuvwxyz ("      12)  concatenation of strarr[4] and strarr[5]
> 
> Two strings are the longest: "folingtrashy" and "abcdefuvwxyz".
> The first that came is "folingtrashy" so 
> longest_consec(strarr, 2) should return "folingtrashy".
> 
> In the same way:
> longest_consec(["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2) --> "abigailtheta"
> ```
> 
> n being the length of the string array, if `n = 0` or `k > n` or `k <= 0` return "" (return `Nothing` in Elm, "nothing" in Erlang).
> 
> #### Note
> 
> consecutive strings : follow one after another without an interruption

<details><summary>解答</summary>

```js
function longestConsec(strarr, k) {
  const n = strarr.length
  if(n === 0 || k > n || k <= 0) {
    return ""
  }
  
  let max = ""
  for(let i = 0; i < n+1-k; i++) {
    const joined = strarr.slice(i, i+k).join("")
    if(max.length < joined.length) {max = joined}
  }
  return max
```

簡単に解説すると、まずエラーになるケースは先に排除していますね。

メインのロジック部分は、`slice()`を使用し、配列の特定の要素から特定の要素までを取得→つなげて、今までの最大のものと比較しています。
最初は作成した文字列を新しい配列に入れていましたが、メモリ消費が多かったので変更しました。
</details>

`slice`というメソッドを完全に忘れてて、連想配列の書き方も怪しかったですw
久しぶりにやってみるとやっぱいいですね。

ただ、これだけじゃ再帰欲が満たされないので、Haskellの過去の解答を見てみましょう。

# 過去やった問題（Haskell）
```hs
module FindMaximumAndMinimumValuesOfAList (minimum, maximum) where

import Prelude hiding (minimum, maximum)

minimum :: [Int] -> Int
minimum [x] = x
minimum (x:xs) = min x (minimum xs)

maximum :: [Int] -> Int
maximum [x] = x
maximum (x:xs) = max x (maximum xs)
```

美しい・・・無駄な部分が一切ありません。
今回の問題は、「配列の中の最小・最大を返す関数を自作しろ」「2つの引数を取り、どちらが小さい・大きいかを返す`min` / `max` はあるよ」というものですね。

1. `minimum`は`[int]` (intの配列)を受け取り、単一の`int`を返す
2. 配列の中身が一つのとき (`[x]`)、それを返す (`= x`)
   （これは再帰の終了条件になります。）
3. `minimum`は受け取った配列を先頭とそれ以外に分割し (`(x:xs)`)、先頭`x`とそれ以外の中で最小のもの`minimum xs`のどちらがより小さいか比較する（`min`）
  
つまり、
`min x (minimum xs)` = `min x (min x' (minimum xs')) = `min x (min x' (min x'' (minimum x'')))`・・・
と、配列の最後の１つになるまで式を展開します。
このように、関数の中で関数自身を呼び出すことを再帰と言います。

具体例を出すと、配列が`[1, 5, 2, 4]`だったとき、
`minimum (x:xs) = min x (minimum xs)`
= `minimum (1:1以外) = min 1 (minimum 1以外)`
= `min 1 (min 5 (minimum 1と5以外))`
= `min 1 (min 5 (min 2 minimum 1と5と2以外))`
  この時、1と5と2以外というのが4しかないので、`minimum 1と5と2以外`は`minimum [4]`となります。`[x]`なら`x`を返す、と設定していましたので、`minimum [4]`は`4`を返します。
= `min 1 (min 5 (min 2 4))`
このような式ができあがります。
後は順番に計算していくだけですね。`min 2 4`は`2`を返します。
= `min 1 (min 5 2)`
= `min 1 2`
= `1`
`[1, 5, 2, 4]`の配列から、単一の最小値`1`を取得できました！

改めて式を振り返りましょう。

```hs
minimum :: [Int] -> Int
minimum [x] = x
minimum (x:xs) = min x (minimum xs)
```

何をやってるか見てわかる、超シンプルなのにあれだけの計算をしてる。
また、配列がどんなに大きくても（理論上）行き詰まることはない。
美しいですね・・・

ちなみに、問題を見たい方はこちらです。

https://www.codewars.com/kata/577a98a6ae28071780000989

8kyu（最も簡単なレベル）の問題です。
Haskell以外でも書けるので、codewarsやったことない方はやってみてください！

# おわりに

満足！🤗

次は何を書こうかしら・・・Codewarsで欲を満たす