[paiza]アルミ缶の上にある。。。（みかんの仕分け (paizaランク C 相当)

# 仕分けと聞くと。。。
【2位じゃダメなんでしょうか？】の2位にすらなれなかった人が思い出されるなぁ。。。
仕事をするうえでも、タスクの仕分けを上手くして順序・効率よく作業が出来るようにしないといけないですね。

https://paiza.jp/works/mondai/c_rank_skillcheck_archive/mikan

# チェック処理とかは端折ってる
/** ここから定型文 */
ここで記載したクラスについては、
[こっちの記事](https://qiita.com/AsilHatake/items/40204293bdf59cb9f9d8)に書いてある、標準入力をList化したりしてるMainクラスから呼び出す予定だし・なんか継承したりしてるYO!!

ちな、Mainを実行して標準入力から入力するのクソ面倒くさいので、
Java編については問題の入力例をパラメータにしたテストクラスとかも作って公開するYO!!

<details open><summary>開発・実行環境はこんな感じ</summary>

- VSCode
- Java 17
- jUnit 5.9
- maven

pom.xmlはこんな感じ

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jp.co.asil</groupId>
    <artifactId>paiza202408</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.9.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
```

</details>
/** ここまで定型文 */

## 実装クラス 
```java:Mikan.java
package jp.co.asil.paiza202408;

import java.util.List;
import java.util.stream.Collectors;

public class Mikan extends Question {

  public Mikan(List<String> list) {
    super(list);
  }

  /**
   * あなたはみかん農園を営んでいます。
   * 
   * 収穫の季節になると、あなたはみかんを収穫し、重さごとに仕分けなければいけません。
   * 
   * 仕分け作業は非常に時間がかかる作業なので、あなたはみかんを重さごとに仕分けてくれるプログラムを書くことにしました。
   * 
   * みかんはある定数 N の倍数のうち、正の整数の重さが書かれた箱に仕分けられます。
   * 
   * 例えば N = 10 の時、10 g, 20 g, 30 g ... のように仕分けられます。
   * 
   * そして、そのみかんの重さが一番近い数の重さに仕分けられます。
   * 重さが一番近い箱が複数ある場合、数が大きい方の箱に仕分けられます。
   * 
   * 入力例 1 は以下のようになります。
   * 10 3
   * 24
   * 35
   * 3
   * 
   * 24 g のみかんはより値の近い 20 g と書かれた箱に仕分けられます。
   * 35 g のみかんは 30 g, 40 g の箱と差が同じです。この場合は数の大きい方の 40 g の箱へ仕分けてください。
   * 0g に仕分けられることはないので、一番小さい重さに仕分けてください。
   * 
   */
  @Override
  public List<String> answer() {
    // 1行目の箱のサイズとみかんの個数を取得
    int[] conds = List.of(list.get(0).split(" ")).stream().mapToInt(Integer::parseInt).toArray();
    // みかんリスト
    return list.subList(1, conds[1] + 1).stream().mapToInt(Integer::parseInt).map(mikan -> {
      if (mikan < conds[0]) {
        // 0 gに仕分けられないので、1番小さい重さを出力
        return conds[0];
      } else if (mikan % conds[0] == 0) {
        // ぴったりサイズならそのまま出力
        return mikan;
      } else {
        int near = Math.floorDiv(mikan, conds[0]);
        // 近いサイズ
        int near1 = near * conds[0];
        // 次のサイズ
        int near2 = (near + 1) * conds[0];
        // diff
        int diff1 = mikan - near1;
        int diff2 = near2 - mikan;
        return diff1 >= diff2 ? near2 : near1;
      }
    }).mapToObj(String::valueOf).collect(Collectors.toList());
  }
}
```

## テストクラス 
```java:MikanTest.java
package jp.co.asil.paiza202408;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import java.util.List;

import org.junit.jupiter.api.Test;

public class MikanTest {
  @Test
  void testAnswer1() {
    Mikan testClass = new Mikan(List.of("10 3",
        "24",
        "35",
        "3"));
    assertArrayEquals(testClass.answer().toArray(), new String[] { "20",
        "40",
        "10" });
  }

  @Test
  void testAnswer2() {
    Mikan testClass = new Mikan(List.of("50 3",
        "40",
        "90",
        "10"));
    assertArrayEquals(testClass.answer().toArray(), new String[] { "50",
        "100",
        "50" });
  }

  @Test
  void testAnswer3() {
    Mikan testClass = new Mikan(List.of("3 2",
        "9",
        "5"));
    assertArrayEquals(testClass.answer().toArray(), new String[] { "9",
        "6" });
  }
}
```

# かいせつ
streamで数値変換した後のmapで箱のサイズを判定して返却、
その後のmapToObjでStringに変換し再度List化って感じのラムダ式になってます。

ちなみにmapToInt/mapToObjをしないような作りでも書けるけど、
結局のところ数値変換と文字列変換が判定してる部分mapの中に入っちゃうため、
直感的・シンプルに書くなら後述のコードより前述のコードのほうがいいかなと思う。
※完全に作り手の趣味の世界だけど。。。

```java:mapToInt/mapToObj使わない版
  public List<String> answer() {
    // 1行目の箱のサイズとみかんの個数を取得
    int[] conds = List.of(list.get(0).split(" ")).stream().mapToInt(Integer::parseInt).toArray();
    // みかんリスト
    return list.subList(1, conds[1] + 1).stream().map(mikanStr -> {
      int mikan = Integer.parseInt(mikanStr); // XXX 結局ココで変換しちゃう
      if (mikan < conds[0]) {
        // 0 gに仕分けられないので、1番小さい重さを出力
        return String.valueOf(conds[0]); // XXX 結局ココで変換しちゃう
      } else if (mikan % conds[0] == 0) {
        // ぴったりサイズならそのまま出力
        return mikanStr;
      } else {
        int near = Math.floorDiv(mikan, conds[0]);
        // 近いサイズ
        int near1 = near * conds[0];
        // 次のサイズ
        int near2 = (near + 1) * conds[0];
        // diff
        int diff1 = mikan - near1;
        int diff2 = near2 - mikan;
        return String.valueOf(diff1 >= diff2 ? near2 : near1); // XXX 結局ココで変換しちゃう
      }
    }).collect(Collectors.toList());
  }
```