数字の配列を降順にソートする #java

概要

  • 数値の配列を降順にソートされたリストにする
  • Stream の sorted を使う
  • Collections の reverseOrder で降順になる

サンプル

int[] nums = {3, 6, 8, 1, 5, 4, 7, 9, 2};

List<Integer> sorted = Arrays.stream(nums).boxed()
        .sorted(Collections.reverseOrder())
        .collect(Collectors.toList());

System.out.println(sorted); // [9, 8, 7, 6, 5, 4, 3, 2, 1]

補足

  • sorted には Comparator を渡せる
  • Comparator には comparing という生成メソッドがある
  • プリミティブ型には comparingInt のように専用のものが用意されている

参考

JavaScript で隔週判定する #javaScript

概要

GAS (Google Apps Script) のトリガーは隔週実行に対応していない。

なので、隔週判定を自前で実装してみる。

考え方

  • 「基準日」と「判定日」を引数で渡す
  • 「基準日」と「判定日」の経過時間を算出する
  • 経過時間を一週間の経過時間で割る
  • 結果が偶数であれば、「判定日」は「基準日」から見て隔週日であると判定する

実装

// base: 基準日, target: 判定日
const isBiweeklyDay = (base: Date, target: Date) : boolean => {
  // 日付以下を切り捨て
  const baseDate = new Date(base.getFullYear(), base.getMonth(), base.getDate())
  const targetDate = new Date(target.getFullYear(), target.getMonth(), target.getDate())

  if (baseDate > targetDate) {
    // target の方が過去
    return false
  }

  // 経過時間
  const passTime = targetDate.getTime() - baseDate.getTime()

  // 経過時間を一週間で割って、偶数なら隔週
  const weekTimes = 604800000
  return (passTime / twoWeekTimes) % 2 === 0
}

テスト

jest で書いたサンプル

describe('基準日が 2020-01-01 の場合' => {
  // month index が 0 始まりなのは分かりにくいので
  const JANUARY = 0
  const baseDate = new Date(2020, JANUARY, 1)

  test('2020-01-08 は false', () => {
    expect(isBiweeklyDay(baseDate, new Date(2020, JANUARY, 7))).toBeFalsy()
  })

  test('2020-01-15 は true', () => {
    expect(isBiweeklyDay(baseDate, new Date(2020, JANUARY, 15))).toBeTruthy()
  })
})

配列を任意のグループに分ける #javaScript

概要

JavaScript で配列を任意のグループに分ける。

例えば 7 人を 3 グループに分けると 3人-2人-2人みたいに分けたい。

考え方

  • 「配列」と「分けたい数」を引数で受け取る
  • まず割り切れる分を分けてしまう
  • 余りを改めて配る

素数が 7 だと 7 / 3 = 2 余り 1 になる。

まず 2-2-2 に分けたあと、余った分を先頭に追加して 3-2-2 にする。

実装

const splitArray = (array, splitSize) => {
  // まず割り切れる分を分ける
  const itemCount = Math.floor(array.length / splitSize)
  const splited = []
  for (let i = 0; i < splitSize; i++) {
    if (i === 0) {
      splited.push(array.slice(i, itemCount ));
      continue
    }
    splited.push(array.slice(itemCount * i, (itemCount * (i + 1))));
  }

  //  余りを配り直す
  const fraction = array.length % splitSize
  if (fraction === 0) {
    return splited
  }
  for (let i = 0; i < fraction; i++) {
    (splited[i]).push(array[array.length - (fraction-i)])
  }

  return splited
}

テスト

たとえば jest で書くなら。

test('7人を3つのグループに分ける', () => {
  const array = [1, 2, 3, 4, 5, 6, 7]
  const splitSize = 3
  expect(splitArray(array, splitSize)).toMatchObject([
    [1, 2, 7],
    [3, 4],
    [5, 6]
  ])
})

問題点

このやり方だと余りをあとから配るので、先頭のグループが [1, 2, 7] になってしまう。

これを [1, 2, 3] にするとしたら、どうするか。

  • 一度要素を総なめして、グループ分けをマークする
  • マークに沿って要素を詰め直す

こっちの方がよさそうな気がした。

もっとスマートなやり方もある気がする。

アジャイルコーチングを読んだ

アジャイルコーチング

アジャイルコーチング

永らく積まれていたのだが、ようやく読んだ。

僕はチームをリードする立場になったことはあってもコーチという立場になったことはない。

ただチームビルディングや開発プロセスをメンテナンスする時に自分が考えていることと、かなり近いことがいい感じにまとまってるなと思った。

自分のチームビルディング、うれしいことに褒めてもらえることが時々ある。 ただ状況に振る舞いが左右されることが多いので、一貫した考えをうまく言語化して伝えるのが難しいと感じていた。

もし、チーム作りみたいなものをスキルとして学ぶとしたら、この本を一緒に読みながら議論していくといいのかななんて思った。

気になったこと

この本はアジャイルコーチに向けた本だと思うのだけれど、紹介されている内容はチーム開発のスキルだと思う。 (もちろん、それを助ける人がいてもいいとは思うんだけど)

コーチングじゃなくて、チーム開発のスキルとして広まって欲しいことがたくさんあるなと思った。

アジャイルコーチング読書メモ · GitHub

テストコードでのヘルパーとか重複とか

テストコードでのヘルパーとか重複について考えた。

gihyo.jp

ちょっと調べたら、少し前のだけれども大御所の人たちの記事を見つけた。

僕もテストコード内のヘルパーや重複にはかなり慎重派。

もちろん見通しのよさや独立性っていう話もあるんだけれども、それよりも「安心したい」っていうモチベーションが強いかもしれない。

テストコードはある意味命綱だから、テストコード自体を信頼できるようにしておきたくて、シンプルに保ちたいという考え。

とはいえ重複絶対嫌とかそういうことではなくて、「共有は慎重に」ということ。

ヘルパを作るなら、ヘルパ自体を十分にテストしたいし、そのコストに見合うタイミングで導入すればいいと思っている。

TDD Bootcamp だったかでいいなと思ったのが、「パラメータライズドテストを検討するのは 3ケース目くらいから」という話。

感覚的にはそれに似ている。

CircleCI で MySQL にパラメータを渡す #CircleCI

TL;DR

command 要素を使うとパラメータを渡せる。

- image: circleci/mysql:5.7-ram
  environment:
    MYSQL_ROOT_PASSWORD: password
    MYSQL_DATABASE: test
  command: ['--character-set-server=utf8mb4']

こんな感じにすると動く。

経緯

Invalid datetime format: 1292 Incorrect datetime value: ‘0000-00-00 00:00:00’

CI を導入したら、テストデータ登録でエラーが発生。

sql_mode の設定が原因であった。

現行の DB の sql_mode が空になっていたので、とりあえず設定を揃えることで回避できないかと考えた。
(本当は STRICT でも動くようにしたい)

MySQL

cnf ファイルを用意してもいいのだが、なんかサクッとやる方法ないかなと調べてみる。

MySQL のイメージ自体は --character-set-server=utf8mb4 みたいな感じで渡せるようだ。

hub.docker.com

CircleCI

設定のリファレンスを読むと、 command という設定があるのを発見。

値ありオプションの例がなかったけど、そのまま渡してあげれば大丈夫なようだ。

circleci.com

command: ['--sql-mode=']

これでよかったっぽい。

参考

MySQL コンテナの起動を待つ #mysql #docker

概要

Docker で MySQL コンテナの起動を待つ方法まとめ

nc で待つ

nc コマンドで待つ。

CircleCI の Example にあった。

for i in `seq 1 10`;
do
  nc -z 127.0.0.1 3306 && echo Success && exit 0
  echo -n .
  sleep 1
done
echo Failed waiting for MySQL && exit 1

dockerize で待つ

これも CircleCI の doc で知った。

-wait を使うことで、起動を監視できる。

CircleCI の公式イメージだと大体インストールされている気がする。

dockerize -wait tcp://localhost:3306 -timeout 1m

github.com

初期化を待つ

nc や dockerize だと、起動の確認までしかできない。

起動時のデータ投入などで初期化中の場合、エラーになってしまうので別途待機する必要がある。

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 102

初期化エラーの場合、mysql クライアントに上記のようなエラーが帰ってくるのでそれを grep することで判定してみた。

for i in $(seq 1 10);
do
  (mysql -h 127.0.0.1 -P 3306 2>&1 1>/dev/null | grep "ERROR 2013 (HY000)" 1>/dev/null) \
    && : || exit 0
  echo -n .
  sleep 1
done
echo ""

2>&1 1>/dev/null

コマンド結果のエラー出力をパイプでつなげるために標準出力にリダイレクトしている。

標準出力自体は捨ててる。

&& : || exit 0

A && B || C とすることで三項演算子っぽくしている。

: は何もせずに終了ステータス0を返す。

「エラーが初期化エラーだったら何もしない」「エラーが初期化エラー意外であれば exit 0 」という風にしている。

参考