Kotlinのuntilを完全に使いこなすたった12の方法

Kotlinのuntil関数を使用したコードのイラストKotlin
この記事は約12分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Kotlinのuntil

これを聞いて、「ああ、なんとなく使ったことがある」と思われる方もいるかと思います。

しかし、「untilは実際にどのような仕組みで、どのように使うのか?」という具体的な内容までしっかりと理解している方は少ないのではないでしょうか。

この記事では、Kotlinのuntilを完全に使いこなすための手法を、初心者から上級者までの読者に向けて、わかりやすく解説します。

この記事を読めば、untilに関する深い知識と実践的な技術を身につけることができるようになります。

●Kotlinのuntilとは

Kotlinのuntilは、ある値から別の値の手前までの範囲を生成するための関数です。

主にforループでの範囲指定に用いられることが多いですが、その用途はそれだけに留まりません。

○untilの基本概念

Kotlinで数値の範囲を表現する際には、..演算子がよく用いられます。例えば、1..5と記述することで、1から5までの範囲を生成できます。

しかし、この..演算子は終端の数値も範囲に含むため、終端の手前までの範囲を取得したい場合にはuntilを使用します。

untilは、開始値から終端値の手前までの範囲を生成します。

言い換えれば、開始値は範囲に含まれ、終端値は範囲に含まれないという特徴があります。

これにより、0からある値手前までの範囲や、リストや配列のインデックスを扱う際に非常に役立ちます。

結果として、untilは範囲の生成をより柔軟に、そして直感的に行うことができる強力なツールとなります。

この基本的な特性を理解することで、untilの更なる活用の道が広がります。

●untilの使い方

Kotlinで数値やオブジェクトの範囲を表現する際に、untilは頻繁に用いられる関数の一つです。

しかし、単なる範囲指定のツールとしてだけでなく、多彩な使い方が可能です。

それでは、具体的な使い方とサンプルコードを通して、untilの魅力を深く探ってみましょう。

○サンプルコード1:基本的な範囲の作成

Kotlinにおける範囲の基本的な生成には..演算子を用います。

しかし、終端の数値を範囲から除外したい場合にはuntilが役立ちます。

fun main() {
    for (i in 1 until 5) {
        println(i)
    }
}

このコードでは、1から4までの整数を順番に出力しています。

5は範囲に含まれていないため、出力されません。

○サンプルコード2:インデックスを使ったリストの操作

untilはリストや配列の操作時にも役立ちます。

特にインデックスを使って要素にアクセスする際に便利です。

fun main() {
    val fruits = listOf("apple", "banana", "cherry", "date")
    for (index in 0 until fruits.size) {
        println(fruits[index])
    }
}

このコードでは、リストfruitsのすべての要素をインデックスを使って順番に出力しています。

リストのサイズを超えることなく、全ての要素にアクセスすることができます。

○サンプルコード3:ステップを指定しての範囲作成

untilと併用してstep関数も使用することで、特定のステップ幅で範囲を生成することができます。

fun main() {
    for (i in 0 until 10 step 2) {
        println(i)
    }
}

このコードでは、0から9までの整数を2つ飛ばしで出力しています。

具体的には、0、2、4、6、8という数値が順番に出力されることとなります。

●untilの応用例

until関数はKotlinの範囲表現において基本的な使い方だけでなく、さまざまな応用が可能です。

実用的なシチュエーションに合わせた使い方を学ぶことで、より幅広い場面での活用が期待できます。

○サンプルコード4:カスタムクラスの範囲作成

Kotlinでは、カスタムクラスでuntilを活用することもできます。

ここでは、独自のクラスDatePointを定義し、その範囲を作成する例を紹介します。

data class DatePoint(val year: Int, val month: Int) : Comparable<DatePoint> {
    override fun compareTo(other: DatePoint): Int {
        return when {
            this.year != other.year -> this.year - other.year
            else -> this.month - other.month
        }
    }
}

operator fun DatePoint.rangeTo(other: DatePoint) = DateRange(this, other)

class DateRange(override val start: DatePoint, override val endInclusive: DatePoint) : ClosedRange<DatePoint>

fun main() {
    val start = DatePoint(2023, 1)
    val end = DatePoint(2023, 6)
    if (DatePoint(2023, 3) in start..end) {
        println("DatePoint(2023, 3)は範囲内です。")
    }
}

このコードでは、DatePointクラスを定義して年と月を表現し、その間の範囲をDateRangeとして表現しています。

このようにカスタムクラスでもuntilと同様の範囲操作が行えるのはKotlinの強みの一つです。

○サンプルコード5:日付の範囲を作成

Kotlinでは、標準ライブラリのLocalDateを活用して、日付の範囲も容易に作成できます。

ここでは、2023年1月1日から2023年6月1日までの日付範囲を作成し、その中で特定の日付が含まれているかを確認する例を紹介します。

import java.time.LocalDate

fun main() {
    val startDate = LocalDate.of(2023, 1, 1)
    val endDate = LocalDate.of(2023, 6, 1)
    for (date in startDate..endDate.minusDays(1)) {
        println(date)
    }
}

このコードを実行すると、2023年1月1日から2023年5月31日までの日付が順番に出力されます。

日付の範囲操作もuntilを駆使して柔軟に行うことができます。

○サンプルコード6:特定の条件下での範囲の利用

Kotlinのuntil関数は、特定の条件下で範囲を作成する際にも非常に役立ちます。

例えば、あるリストから特定の条件に一致する要素の範囲だけを取得する場合などにこの特性を活用することができます。

ここでは、1から100までの整数の中で、3で割り切れる数字の範囲だけを取得する例を紹介します。

fun main() {
    val numbers = 1..100
    val divisibleByThree = numbers.filter { it % 3 == 0 }

    for (num in divisibleByThree) {
        println(num)
    }
}

このコードでは、1から100までの範囲の中で、3で割り切れる数字のみをフィルタリングしています。

その結果、3, 6, 9, … 99という数字が出力されます。

○サンプルコード7:他の関数との連携

until関数は、他の関数と連携して使うことでさらに強力になります。

ここでは、untilmap関数を組み合わせて、1から10までの数字を2倍にする例を紹介します。

fun main() {
    val range = 1 until 11
    val doubled = range.map { it * 2 }

    doubled.forEach { println(it) }
}

このコードでは、1から10までの範囲を作成し、その各要素を2倍にしています。

結果として、2, 4, 6, … 20が順に出力されます。

○サンプルコード8:マップのキーの範囲作成

Kotlinでは、マップのキーを範囲として扱うこともできます。

これにより、特定のキー範囲に属するエントリだけを取得することが可能です。

ここでは、マップの中から特定のキー範囲のエントリのみを取得する例を紹介します。

fun main() {
    val fruitsPrice = mapOf("apple" to 100, "banana" to 150, "cherry" to 200, "date" to 250, "elderberry" to 300)
    val selectedFruits = fruitsPrice.keys.filter { it in "banana".."date" }

    for (fruit in selectedFruits) {
        println("$fruit: ${fruitsPrice[fruit]}円")
    }
}

このコードでは、”banana”から”date”までのキーを持つエントリのみをフィルタリングしています。

その結果、banana, cherry, dateの価格が出力されます。

●注意点と対処法

Kotlinでのuntil関数の活用は非常に便利ですが、適切に利用しないとエラーや予期せぬ挙動が発生することがあります。

ここでは、そのような一般的なエラーや注意点、そしてそれらを適切に対処する方法について詳しく解説していきます。

○サンプルコード9:常見のエラーシチュエーションとその対処法

until関数を使って範囲を作成する際、開始値が終了値より大きい場合、範囲は空になります。

これは予期せぬ挙動を引き起こす可能性があります。

例として、次のコードを考えます。

fun main() {
    val range = 10 until 5
    println(range.toList())
}

このコードでは、10から5までの範囲を作成しようとしています。

しかし、結果は空のリストとして出力されます。

このようなシチュエーションに遭遇した際の対処法として、開始値と終了値の大小関係をチェックする方法が考えられます。

もし開始値が終了値よりも大きい場合は、範囲を作成する前にエラーメッセージを出力するなどしてユーザーに警告することができます。

○サンプルコード10:範囲外の値を扱う場合の対処法

untilで作成した範囲外の値にアクセスしようとすると、エラーが発生することがあります。

特に、配列やリストのインデックスとして範囲を使用する場合、このような問題が起こる可能性が高まります。

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    for (i in 0 until numbers.size + 1) {
        println(numbers[i])
    }
}

このコードでは、numbersリストの要素を出力しようとしていますが、iの範囲がnumbers.size + 1となっているため、最後のループで範囲外のインデックスにアクセスしようとしてエラーが発生します。

このようなエラーを防ぐためには、範囲を正確に指定することが重要です。

上記の例では、i in 0 until numbers.sizeとすることで、正しい範囲内でのアクセスが保証されます。

●カスタマイズ方法

Kotlinのuntil関数はそのままでも非常に有用ですが、特定のニーズに合わせてカスタマイズすることで、さらに効果的に活用することができます。

ここでは、until関数のカスタマイズ方法について、具体的なサンプルコードを交えて説明します。

○サンプルコード11:自分だけのuntil拡張関数の作成

Kotlinでは拡張関数を利用して、既存のクラスに新しい関数を追加することができます。

この特徴を活用して、until関数をカスタマイズすることが考えられます。

例えば、Intに特定の値までの範囲を作成し、その範囲の数字だけを二乗した結果のリストを返す拡張関数を作成することができます。

fun Int.untilSquared(end: Int): List<Int> {
    return (this until end).map { it * it }
}

fun main() {
    val result = 1.untilSquared(5)
    println(result)  // 出力結果:[1, 4, 9, 16]
}

このコードでは、IntuntilSquaredという拡張関数を追加しています。

この関数を使用すると、指定した範囲の数値を二乗した結果のリストを取得することができます。

○サンプルコード12:異なるデータタイプへのカスタムuntil

until関数は数値型に適用されることが多いですが、異なるデータタイプにも適用することで、さまざまなシチュエーションでの利用が考えられます。

例えば、String型に対してもuntil関数のような機能を持つ拡張関数を作成することができます。

ここでは、文字列の範囲を取得する拡張関数の例を紹介します。

fun String.untilStr(end: String): List<String> {
    val startIndex = this[0].code
    val endIndex = end[0].code
    return (startIndex until endIndex).map { it.toChar().toString() }
}

fun main() {
    val result = "A".untilStr("E")
    println(result)  // 出力結果:["A", "B", "C", "D"]
}

このコードでは、StringuntilStrという拡張関数を追加しています。

この関数を使用すると、指定した範囲の文字列のリストを取得することができます。

このように、異なるデータタイプに対してもuntilのような関数をカスタマイズして適用することで、多様な処理を効率的に実現することができます。

まとめ

Kotlinのuntil関数は、範囲を作成する際に非常に便利なツールとして実装されています。

この記事では、until関数の基本的な使い方から、応用例、注意点、さらにはカスタマイズ方法までを幅広く解説しました。

初心者から上級者まで、この記事を通じてuntil関数の深い理解と活用方法を学ぶことができたことでしょう。

Kotlinの魅力は、単なる基本機能だけでなく、その拡張性やカスタマイズの自由度にあります。

until関数もその一例で、日常のプログラミング作業において非常に役立つ機能となっています。

今後もKotlinを学び、実践していく中で、このuntil関数を始めとした多くの便利な関数や特性を活用し、効率的かつ楽しいプログラミングライフを送ってください。