1365. How Many Numbers Are Smaller Than the Current Number

LeetCode の挑戦ログ

Problem

https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/

  • 数字の配列が与えられる
  • それぞれの値より少ない値がいくつ含まれているか数える
  • その数を同じ index の配列にして返す

Solution

class Solution {
    public int[] smallerNumbersThanCurrent(int[] nums) {
        return Arrays.stream(nums)
                .map(base -> (int) Arrays.stream(nums).filter(num -> num < base).count())
                .toArray();
    }
}

Impressions

  • count に詰め替えているところは可読性を考えると関数に切り出してもいいかも
  • 結局コードの考え方としては総当たりに近いのでもうちょっといいアプローチがありそう

1342. Number of Steps to Reduce a Number to Zero

LeetCode の挑戦ログ

Problem

https://leetcode.com/problems/number-of-steps-to-reduce-a-number-to-zero/

  • 正の整数が渡される
  • 偶数なら 2 で割る、奇数なら 1 を引く
  • 0 になるまでの回数を数える

Solution

class Solution {
    public int numberOfSteps(int num) {
        return countSteps(num);
    }

    private int countSteps(int num) {
        int steps = 0;
        while (num != 0) {
            num = reduce(num);
            steps += 1;
        }

        return steps;
    }

    private int reduce(int num) {
        return num % 2 == 0 ? (num / 2) : (num - 1);
    }
}

Impressions

  • 最初は再起で書いたけど、ループに書き直した
  • Java には言語での末尾再帰最適化はないらしい
  • Kotlin の tailrec は便利だな

再起で書いたやつ

class Solution {
    public int numberOfSteps(int num) {
        return countSteps(num, 0);
    }

    private int countSteps(int num, int steps) {
        num = reduce(num);
        steps += 1;

        if (num == 0) {
            return steps;
        }

        return countSteps(num, steps);
    }

    private int reduce(int num) {
        return num % 2 == 0 ? (num / 2) : (num - 1);
    }
}

PHPUnit のモックで、引数に応じて戻り値を変更する #php #PHPUnit

概要

  • returnValueMap を使うと引数に応じて戻り値を変更できる
  • 例外を返したいときは returnCallback() を使うと便利

returnValueMap を使う

returnValue に [引数, 戻り値] の配列を渡すと、引数に応じた戻り値を返す Mock を作れる。

引数が複数ある場合は、 [引数1, 引数2, 戻り値] のような形式にしてあげればよい。

// Mock を作成
$mock = $this->createMock(HogeClass::class);

// returnValueMap に [引数, 戻り値] の配列を渡す
$mock->method('doSomething')
      ->will($this->returnValueMap(
        [
          ['arg1', 'ret1'],
          ['arg2', 'ret2'],
        ]
      ));

// 引数に応じた値が帰ってくる
$this->assertSame('ret1', $mock->doSomething('arg1'));
$this->assertSame('ret2', $mock->doSomething('arg2'));

例外を返す場合は returnCallback を使うとよさそう

returnValueMap だと通常の戻り値と例外のケースを同時に同じ Mock ができなそう。

返り値を callback にできる returnCallback を応用して実現してみる。

$mock->method('doSomething')
      ->will($this->returnCallback(
        // doSomething が実行されると、callback が呼ばれる
        function ($arg) {
          if ($arg === 'arg1') {
            return 'ret1';
          } elseif ($arg === 'arg2') {
            return 'ret2';
          } elseif ($arg === 'invalid') {
            // 引数によって例外を投げる
            throw new InvalidArgumentException('doSomething called by invalid argumnet. Input was: '.$arg);
          }

          return 'retDefault';
        }
      ));

引数と返り値を切り出す

returnCallback でやりたいことは実現できたのだが、分岐を追記していくスタイルは辛いので、処理を切り分ける。

// 引数と戻り値の紐付けを切り出す
$map = [
  'arg1' => function () { return 'ret1'; }],
  'arg2' => function () { return 'ret1'; }],
  'invalid' => function () { throw new InvalidArgumentException('doSomething called by invalid argumnet. Input was: '.$arg); }],
  'default' => function () { return 'retDefault'; }],
];

$mock->method('doSomething')
      ->will($this->returnCallback(
        function ($arg) {
          if ($map[$arg]) {
            return $map[$arg]();
          }

          return $map['default']();
        }
      ));

補足

そもそも Mock に色々やらせすぎたり、 Mock を使いすぎたりするのは微妙だと思う。

ただ Mock をケースごとに差し替えるのは大変なときにはこういうやり方が使えそう。

参考

課題に正面から取り組むこと

経験を積むと、実現が難しい方法で苦しんでるときに、より容易な回避方法が浮かぶようになる。

手元に並べられる選択肢が増えるというか。

それはいいことなんだけど、「より最適な解として」別の手段を選んでるつもりで、「難しい方法を避けるために」別の手段を選んではいないか。

特に「納期」みたいなものは分かりやすく、そして言い訳にしやすい。

「今回はスケジュールが厳しいからこの方法にしよう」

安全策は最後のライフラインとして傍らに確保しつつ、正面から立ち向かう気持ちを忘れずにいたい。

私は弱い人間で、すぐ逃げようとするので。

DataGrip で クリアテキスト認証 を使う #DataGrip

概要

IAM 認証 による RDS 接続をする際などに、 MySQL のクリアテキスト認証が必要になる。

DataGrip から利用する方法をまとめておく。

おそらく Jetbrains 製品の Database Viewer でも同じ方法でできると思う。

参考: IAM認証によるRDS接続を試してみた | Developers.IO

設定方法

  • DataSource の設定項目の Advanced タブを開く
  • authenticationPlugin に com.mysql.cj.protocol.a.authentication.MysqlClearPasswordPlugin を指定する
  • VM environment に LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN=1 を設定する

ドライバーに MySQL for 5.1 を利用している場合

パッケージ名が異なるので、 com.mysql.jdbc.authentication.MysqlClearPasswordPlugin を指定する。

参考

IntelliJ IDEA から MySQL に繋ごうとしたら Communications link failure #IntelliJIDEA

問題

IntelliJ IDEA や DataGrip から MySQL に接続したら、エラーになってしまった。

接続テストでは成功するのに、実際に繋ごうとすると Communications link failure と言われてしまう。

java.io.IOException: Socket is closed. Communications link failure. The last packet successfully received from the server was 24 milliseconds ago. The last packet sent successfully to the server was 30 milliseconds ago.

対応

接続設定の Driver を MySQL から MySQL for 5.1 に変更すると解消した。

接続先の MySQL は 5.6 だったんだけど、ドライバーのバージョンとの相性が原因だろうか。

f:id:su-kun1899:20200226105313p:plain

参考

1207. Unique Number of Occurrences

LeetCode の挑戦ログ

Problem

https://leetcode.com/problems/unique-number-of-occurrences/

  • 整数の配列を渡される
  • 値の登場回数がユニークで構成される場合は true を返す

Solution

class Solution {
    public boolean uniqueOccurrences(int[] arr) {
        Map<Integer, Long> map = Arrays.stream(arr)
                .boxed()
                .collect(Collectors.groupingBy(i -> i, Collectors.counting()));

        int valueCount = map.size();
        long occurrenceCount = map.values().stream().distinct().count();

        return valueCount == occurrenceCount;
    }
}

Impressions

  • 要素の数を数えたいときは、 Collectors#groupingBy の第 2 引数に Collectors.counting() を渡す

References