Scalaでの文字列比較

Scalaでは、文字列を==メソッド*1で比較する。

val s1 = "Hello"
val s2 = "Hello"
s1 == s2 // true

Javaと同じようにequalsメソッドを使用して比較することもできる。

val s1 = "Hello"
val s2 = "Hello"
s1.equals(s2) // true

equalsメソッドと比較して==メソッドの利点は、
nullの場合でもNullPointerExceptionが発生しないこと。

val s1: String = null
val s2 = "Hello"
s1 == s2 // false
s1.equals(s2) // java.lang.NullPointerExceptionが発生する。

*1:AnyRefで定義されている。

Scala Standard Library 2.13.8 - scala.AnyRef

Javaでカレントディレクトリを取得する

やりたいこと

Javaでカレントディレクトリを取得したい。

やりかた

PathクラスのtoAbsolutePathを使用する。
Path(Java SE 11 & JDK 11)

import java.nio.file.Path;

public class PathTest {
    public static void main(String[] args) {
        Path p = Path.of("");
        Path p2 = p.toAbsolutePath();
        System.out.println(p2.toString());
    }
}

実行結果(カレントディレクトリ:/code/sample/java)

/code/sample/java

Pathクラスを生成するときは、Paths.getではなく、Path.ofを使用したほうがいいらしい。 Paths(Java SE 11 & JDK 11)

このクラスは今後のリリースで非推奨になる可能性があるため、このクラスに定義されたgetメソッドではなく、Pathメソッドを経由してPathを取得することをお薦めします。

PostgreSQLで指定した期間の連続した日付を作成する

PostgreSQLで指定した期間の連続した日付を作成します。

やりたいこと

例えば、FROM:2021-04-01、TO:2021-04-30と指定した場合、
2021-04-01
2021-04-02
2021-04-03
(中略)
2021-04-30
といった連続した日付を持った一時的なテーブルを作成します。

月間の実績を日毎に累積して表示してほしい、という要件があったのですが、
単純に実績データのみを取得すると、実績がある日付しか表示されません。
そこで上記の一時テーブルと実績テーブルを外部結合して累積することで対応しました。
SQLのみで実装する必要はあるのか、という点はおいといて、、、)

やりかた

generate_seriesを使用します。

generate_seriesは集合を返す関数です。
詳しくは公式マニュアルを読んでください。
PostgreSQL 12.4文書-9.24. 集合を返す関数

実行例

SELECT
    generate_series::DATE AS date
FROM
    generate_series('2021-04-01'::DATE, '2021-04-30'::DATE, '1 day');

※戻り型はTIMESTAMP型のためDATE型にキャストしています。

実行結果

    date    
------------
 2021-04-01
 2021-04-02
 2021-04-03
 2021-04-04
 2021-04-05
 2021-04-06
 2021-04-07
 2021-04-08
 2021-04-09
 2021-04-10
 2021-04-11
 2021-04-12
 2021-04-13
 2021-04-14
 2021-04-15
 2021-04-16
 2021-04-17
 2021-04-18
 2021-04-19
 2021-04-20
 2021-04-21
 2021-04-22
 2021-04-23
 2021-04-24
 2021-04-25
 2021-04-26
 2021-04-27
 2021-04-28
 2021-04-29
 2021-04-30
(30 rows)

おまけ

月間の実績を累積して取得する例

-- 連続した日付の一時的なテーブル
WITH dates AS (
    SELECT
        generate_series::DATE AS date
    FROM
        generate_series('2021-04-01'::DATE, '2021-04-30'::DATE, '1 day')
)
-- 実績テーブル
, achievements AS (
    SELECT
        '2021-04-05'::DATE AS date 
        , 100 AS value
    UNION ALL
    SELECT
        '2021-04-10'::DATE AS date 
        , 150 AS value 
    UNION ALL
    SELECT 
        '2021-04-15'::DATE AS date 
        , 300 AS value
)
SELECT 
    dates.date 
    , SUM(COALESCE(achievements.value, 0)) OVER (ORDER BY dates.date) AS value
FROM
    dates
LEFT JOIN achievements ON 
    achievements.date = dates.date;

実行結果

    date    | value 
------------+-------
 2021-04-01 |     0
 2021-04-02 |     0
 2021-04-03 |     0
 2021-04-04 |     0
 2021-04-05 |   100
 2021-04-06 |   100
 2021-04-07 |   100
 2021-04-08 |   100
 2021-04-09 |   100
 2021-04-10 |   250
 2021-04-11 |   250
 2021-04-12 |   250
 2021-04-13 |   250
 2021-04-14 |   250
 2021-04-15 |   550
 2021-04-16 |   550
 2021-04-17 |   550
 2021-04-18 |   550
 2021-04-19 |   550
 2021-04-20 |   550
 2021-04-21 |   550
 2021-04-22 |   550
 2021-04-23 |   550
 2021-04-24 |   550
 2021-04-25 |   550
 2021-04-26 |   550
 2021-04-27 |   550
 2021-04-28 |   550
 2021-04-29 |   550
 2021-04-30 |   550
(30 rows)

JavaのStreamで2次元配列を一つの配列にする

仕事で使う機会があったので備忘録です。

やりたいこと

以下のような2次元配列を一つの配列にして、 後続処理に渡したい。

// これを
[["a", "b", "c"], ["d", "e"]]

// こうしたい
["a", "b", "c", "d", "e"]

やり方

StreamのflatMapを使用します。

String[][] twoArray = {
        { "a", "b", "c" }
        , { "d", "e" } 
    };
String[] array = Arrays.stream(twoArray)
    .flatMap(Arrays::stream)
    .toArray(String[]::new);
System.out.println(Arrays.toString(array));

実行結果

[a, b, c, d, e]