プログラムを書こう!

実務や自作アプリ開発で習得した役に立つソフトウェア技術情報を発信するブログ

DartのHashSetから条件に一致する最初の要素を取得する

この記事は 2026 年 8 月 23 日に投稿しました。

目次

  1. はじめに
  2. DartのHashSetから条件に一致する最初の要素を取得する
  3. 条件に一致する要素がない場合にorElseを使用する
  4. firstWhereメソッドとwhereメソッドの違い
  5. firstWhereメソッドを使用する場合の注意点
  6. おわりに

1. はじめに

こんにちは、iOS のエディタアプリPWEditorとその後継PWEditorNextの開発者の二俣です。
2018年5月から毎日技術ブログを更新しています。

今回はDartHashSetから、指定した条件に一致する最初の要素を取得できるfirstWhereメソッドについてです。

目次へ

2. DartのHashSetから条件に一致する最初の要素を取得する

DartHashSetでは、firstWhereメソッドを使用すると、指定した条件に一致する最初の要素を取得できます。

firstWhereメソッドの形式は以下になります。

E firstWhere(
  bool test(E element), {
  E orElse()?,
})

第1引数には、各要素が条件に一致するかを判定する関数を指定します。

この関数がtrueを返した最初の要素が、firstWhereメソッドの戻り値になります。

例えば、次のHashSetがあるとします。

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
  40,
  50,
]);

この中から、

30以上

という条件に一致する最初の要素を取得する場合は、次のように記述できます。

final result = numbers.firstWhere(
  (number) => number >= 30,
);

print(result);

firstWhereに指定した、

(number) => number >= 30

が、各要素について順番に評価されます。

条件を満たす要素が見つかると、その要素が返されます。

実装例

import 'dart:collection';

void main() {
  final numbers = HashSet<int>();

  numbers.addAll([
    10,
    20,
    30,
    40,
    50,
  ]);

  final result = numbers.firstWhere(
    (number) => number >= 30,
  );

  print(result);
}

ただし、HashSetでは要素の反復順序が保証されていません。

そのため、

30

が必ず返されるとは限りません。

例えば、反復時に4030より先に現れた場合は、40が返される可能性があります。

firstWhereメソッドの「最初」とは、

追加した順番で最初

という意味ではなく、

HashSetを反復したときに最初に条件を満たした要素

という意味になります。

文字列に対して使用することもできます。

例えば、

import 'dart:collection';

void main() {
  final languages = HashSet<String>();

  languages.addAll([
    'Dart',
    'Swift',
    'Kotlin',
    'Java',
  ]);

  final result = languages.firstWhere(
    (language) => language.length >= 5,
  );

  print(result);
}

この例では、

language.length >= 5

という条件に一致する最初の文字列を取得します。

SwiftKotlinなどが条件に一致しますが、どちらが返されるかはHashSetの反復順序によって決まります。

条件には、さまざまな判定を指定できます。

例えば、偶数を検索する場合は、

final result = numbers.firstWhere(
  (number) => number.isEven,
);

とできます。

特定の範囲の数値を検索する場合は、

final result = numbers.firstWhere(
  (number) => number >= 20 && number <= 40,
);

とできます。

文字列の先頭を調べる場合は、

final result = languages.firstWhere(
  (language) => language.startsWith('D'),
);

とできます。

文字列に特定の文字列が含まれているかを調べる場合は、

final result = languages.firstWhere(
  (language) => language.contains('lin'),
);

とできます。

このようにfirstWhereメソッドは、

条件に合う要素を1つだけ取得したい

場合に利用できます。

また、firstWhereメソッドはHashSet固有のメソッドではありません。

HashSetIterableとして扱えるため、Iterableで定義されているfirstWhereメソッドを利用できます。

そのため、Listなどでも同じように使用できます。

final numbers = [
  10,
  20,
  30,
  40,
  50,
];

final result = numbers.firstWhere(
  (number) => number >= 30,
);

print(result);

Listの場合は要素の順序が決まっているため、この例では30が返されます。

目次へ

3. 条件に一致する要素がない場合にorElseを使用する

firstWhereメソッドを使用するときに重要なのが、条件に一致する要素が存在しない場合の処理です。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
]);

というHashSetに対して、

final result = numbers.firstWhere(
  (number) => number >= 100,
);

とします。

このHashSetには100以上の要素が存在しません。

条件に一致する要素がなく、orElseも指定されていない場合、firstWhereメソッドはStateErrorをスローします。

そのため、条件に一致する要素が存在しない可能性がある場合は注意が必要です。

orElseを指定する

条件に一致する要素がなかった場合に別の値を返したいときは、orElseを指定できます。

例えば、

import 'dart:collection';

void main() {
  final numbers = HashSet<int>();

  numbers.addAll([
    10,
    20,
    30,
  ]);

  final result = numbers.firstWhere(
    (number) => number >= 100,
    orElse: () => -1,
  );

  print(result);
}

条件に一致する要素がないため、

-1

が返されます。

orElseには、

orElse: () => -1

のように、HashSetの要素と同じ型の値を返す関数を指定します。

文字列の場合は、例えば、

final languages = HashSet<String>();

languages.addAll([
  'Dart',
  'Swift',
  'Kotlin',
]);

final result = languages.firstWhere(
  (language) => language.startsWith('Z'),
  orElse: () => 'Not found',
);

print(result);

とできます。

条件に一致する文字列が存在しないため、

Not found

が返されます。

空のHashSetの場合

空のHashSetに対してfirstWhereメソッドを使用した場合も、条件に一致する要素は存在しません。

例えば、

final numbers = HashSet<int>();

final result = numbers.firstWhere(
  (number) => number > 0,
);

では、StateErrorがスローされます。

orElseを指定しておけば、

final result = numbers.firstWhere(
  (number) => number > 0,
  orElse: () => -1,
);

のように、空の場合でも指定した値を取得できます。

nullを格納できるHashSetの場合

nullを格納できるHashSetでもfirstWhereメソッドを使用できます。

例えば、

import 'dart:collection';

void main() {
  final languages = HashSet<String?>();

  languages.addAll([
    'Dart',
    null,
    'Swift',
    'Kotlin',
  ]);

  final result = languages.firstWhere(
    (language) =>
        language != null &&
        language.length >= 5,
  );

  print(result);
}

この場合、nullを除外しながら、5文字以上の文字列を検索しています。

また、null自体を検索することもできます。

final result = languages.firstWhere(
  (language) => language == null,
);

この場合はnullが見つかればnullが返されます。

ただし、

条件に一致する要素としてnullが返された

場合と、

要素が見つからなかった

場合を区別したいときは、処理方法を検討する必要があります。

例えばorElseでもnullを返すと、

final result = languages.firstWhere(
  (language) => language == 'Java',
  orElse: () => null,
);

結果がnullだったときに、

HashSet内のnullが見つかった
条件に一致する要素がなかった

のどちらなのか、戻り値だけでは判断できないケースがあります。

目次へ

4. firstWhereメソッドとwhereメソッドの違い

firstWhereメソッドと似た用途のメソッドとして、whereメソッドがあります。

どちらも、

指定した条件に一致する要素を検索する

ために利用できます。

ただし、取得する結果が異なります。

firstWhereメソッドは、

条件に一致する最初の1要素

を返します。

一方、whereメソッドは、

条件に一致するすべての要素

Iterableとして返します。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
  40,
  50,
]);

があるとします。

20以上の要素を検索する場合、firstWhereメソッドでは、

final result = numbers.firstWhere(
  (number) => number >= 20,
);

print(result);

とします。

戻り値は条件に一致した1つのintです。

int

一方、whereメソッドを使用すると、

final result = numbers.where(
  (number) => number >= 20,
);

print(result);

条件に一致したすべての要素を含む、

Iterable<int>

が返されます。

つまり、

firstWhere
条件に一致する要素を1つ取得する

where
条件に一致する要素をすべて取得する

という違いがあります。

where().firstとの違い

whereメソッドとfirstプロパティを組み合わせても、条件に一致する最初の要素を取得できます。

例えば、

final result = numbers
    .where(
      (number) => number >= 20,
    )
    .first;

とできます。

これは、

final result = numbers.firstWhere(
  (number) => number >= 20,
);

と似た結果になります。

ただし、

条件に一致する最初の要素を1つだけ取得する

ことが目的であれば、firstWhereメソッドを使用した方が意図が分かりやすくなります。

また、firstWhereメソッドは条件に一致する要素を見つけると、その時点で探索を終了します。

例えば、

import 'dart:collection';

void main() {
  final numbers = HashSet<int>();

  numbers.addAll([
    10,
    20,
    30,
    40,
    50,
  ]);

  final result = numbers.firstWhere((number) {
    print('check: $number');

    return number >= 30;
  });

  print('result: $result');
}

とすると、条件に一致する要素が見つかった後の要素については、判定する必要がありません。

そのため、

条件に一致する要素が1つ見つかればよい

のであれば、firstWhereメソッドが適しています。

一方、

条件に一致する要素をすべて処理したい

場合はwhereメソッドを使用します。

例えば、

final result = numbers.where(
  (number) => number >= 30,
);

for (final number in result) {
  print(number);
}

とすると、条件に一致するすべての要素を処理できます。

使い分けとしては、

条件に一致する1要素だけ必要
firstWhere

条件に一致するすべての要素が必要
where

と考えると分かりやすいでしょう。

目次へ

5. firstWhereメソッドを使用する場合の注意点

HashSetfirstWhereメソッドを使用する場合、いくつか覚えておきたい点があります。

条件に一致する要素がない場合はStateErrorになる

firstWhereメソッドでは、条件に一致する要素が存在せず、orElseも指定していない場合、StateErrorがスローされます。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
]);

final result = numbers.firstWhere(
  (number) => number >= 100,
);

では、条件に一致する要素がありません。

そのため、StateErrorになります。

条件に一致する要素が存在しない可能性がある場合は、

final result = numbers.firstWhere(
  (number) => number >= 100,
  orElse: () => -1,
);

のようにorElseを使用するとよいでしょう。

ただし、

-1

のような値が通常の要素としても存在する可能性がある場合は、

見つからなかったことを表す値

として適切かどうかを考える必要があります。

HashSetの反復順序は保証されない

HashSetfirstWhereメソッドを使用するときに特に注意したいのが、要素の順序です。

HashSetでは、要素の反復順序が保証されていません。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
  40,
  50,
]);

final result = numbers.firstWhere(
  (number) => number >= 30,
);

とします。

条件に一致する要素は、

30
40
50

です。

Listであれば、同じ並びなら最初に条件を満たす30が返されます。

しかし、HashSetでは、

30
40
50

のどれが最初に反復されるかは保証されていません。

そのため、4050が返される可能性もあります。

つまり、

firstWhereを使えば最小の値が取得できる

わけではありません。

例えば、

final result = numbers.firstWhere(
  (number) => number >= 30,
);

は、

30以上の最小値を取得する

という処理ではなく、

反復順序の中で最初に見つかった30以上の値を取得する

という処理になります。

特定の順序に基づいて要素を選択したい場合は、HashSetの反復順序に依存しない方法を使用する必要があります。

例えば、一度Listに変換して並べ替えてから検索する方法があります。

final sortedNumbers = numbers.toList()
  ..sort();

final result = sortedNumbers.firstWhere(
  (number) => number >= 30,
);

print(result);

この場合は昇順に並べ替えているため、30以上の最小の値を取得できます。

条件に一致した時点で探索を終了する

firstWhereメソッドは、条件に一致する要素を見つけると、その要素を返して探索を終了します。

例えば、

final result = numbers.firstWhere((number) {
  print('check: $number');

  return number > 20;
});

では、条件に一致する要素が見つかった後の要素については判定されません。

そのため、

条件に一致する要素が存在するか調べながら、その要素を取得したい

という場合に便利です。

ただし、判定関数の中で副作用のある処理を行う場合には注意が必要です。

例えば、

final result = numbers.firstWhere((number) {
  print(number);

  return number > 20;
});

とした場合、すべての要素がprintされるとは限りません。

条件に一致する要素が見つかった時点で処理が終了するためです。

基本的には、

(number) => number > 20

のように、条件を判定する処理を中心に記述すると分かりやすいでしょう。

戻り値はHashSetではなく要素そのもの

whereメソッドなどとは異なり、firstWhereメソッドはIterableを返しません。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
]);

final result = numbers.firstWhere(
  (number) => number >= 20,
);

の場合、resultの型は、

int

です。

Iterable<int>

や、

HashSet<int>

ではありません。

文字列のHashSetであれば、

final languages = HashSet<String>();

final result = languages.firstWhere(
  (language) => language.startsWith('D'),
);

resultは、

String

になります。

条件に一致する複数の要素を取得したい場合は、firstWhereではなくwhereメソッドを使用します。

final result = numbers.where(
  (number) => number >= 20,
);

HashSet自体は変更されない

firstWhereメソッドは、条件に一致する要素を検索して返すためのメソッドです。

元のHashSetの内容は変更されません。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
]);

final result = numbers.firstWhere(
  (number) => number >= 20,
);

print(result);
print(numbers);

とした場合も、numbersには元の要素が残っています。

firstWhereメソッドは、

要素を削除する
要素を変更する
HashSetを別のコレクションに変換する

といった処理を行うものではありません。

あくまで、

条件に一致する要素を検索して取得する

ためのメソッドです。

firstプロパティとの違い

Iterableにはfirstプロパティもあります。

final result = numbers.first;

firstは、反復順序で最初の要素をそのまま取得します。

一方、firstWhereメソッドでは、

final result = numbers.firstWhere(
  (number) => number >= 20,
);

のように条件を指定できます。

つまり、

first
最初の要素を取得する

firstWhere
条件を満たす最初の要素を取得する

という違いがあります。

ただし、どちらもHashSetで使用した場合は、反復順序が保証されていないことに注意が必要です。

firstWhereはHashSet固有のメソッドではない

firstWhereメソッドはHashSet固有のメソッドではなく、Iterableで利用できるメソッドです。

そのため、

final list = [
  10,
  20,
  30,
];

final result = list.firstWhere(
  (number) => number >= 20,
);

のようにListでも使用できます。

Listでは要素の順序が決まっているため、

条件に一致する最初の要素

の意味が分かりやすくなります。

一方、HashSetの場合は順序が保証されていないため、

条件に一致する要素のうち、どれでもよいので1つ取得したい

という用途に適しています。

もし、

最も小さい値
追加順で最初の値
特定の並び順で最初の値

などを取得したい場合は、HashSetの反復順序だけに頼らない処理を検討するとよいでしょう。

リファレンス

Dart

DartPad

HashSet

Set

Iterable

Iterable.firstWhere

Iterable.first

Iterable.where

目次へ

6. おわりに

DartHashSetから、指定した条件に一致する最初の要素を取得するには、firstWhereメソッドを使用できます。

例えば、

final numbers = HashSet<int>();

numbers.addAll([
  10,
  20,
  30,
  40,
  50,
]);

final result = numbers.firstWhere(
  (number) => number >= 30,
);

とすると、

30以上

という条件に一致する最初の要素を取得できます。

ただし、HashSetでは反復順序が保証されていません。

そのため、

30
40
50

が条件に一致する場合、必ず30が返されるわけではありません。

firstWhereメソッドの「最初」とは、

HashSetを反復したときに最初に条件を満たした要素

という意味になります。

また、条件に一致する要素が存在しない場合、orElseを指定していなければStateErrorがスローされます。

例えば、

final result = numbers.firstWhere(
  (number) => number >= 100,
  orElse: () => -1,
);

とすると、条件に一致する要素がない場合は、

-1

を返せます。

whereメソッドとの違いとして、

firstWhere
条件に一致する最初の1要素を取得する

where
条件に一致するすべての要素をIterableとして取得する

という点があります。

条件に一致する要素が1つだけ必要であれば、

final result = numbers.firstWhere(
  (number) => number.isEven,
);

のようにfirstWhereメソッドを使用すると分かりやすく記述できます。

また、条件に一致した要素が見つかると、その時点で探索を終了します。

そのため、

条件に一致する要素を1つだけ取得したい

場合に適しています。

一方で、HashSetでは要素の順序が保証されないため、

最小の値を取得したい
追加した順番で最初の要素を取得したい

といった用途では注意が必要です。

順序に意味がある場合は、必要に応じてListへ変換して並べ替えるなど、順序を明確にしてからfirstWhereメソッドを使用するとよいでしょう。

firstWhereメソッドは、コレクションから条件に一致する要素を1つだけ検索して取得したい場合に便利なメソッドです。

目次へ


私が技術者として所属している ニューラル では、 組み込み・制御系ソフトウェアを中心に、モバイルアプリや業務アプリなど、さまざまなソフトウェアの開発を行っています。

組み込み分野では、リアルタイムOSを利用したシステム開発をはじめ、弊社製品のハイブリッドOS Bi-OS など、長年培ってきた組み込み・制御系の技術を活かした開発に取り組んでいます。

また、iOS(Swift/SwiftUI)やWindows(C#)をはじめとしたアプリケーション開発、Webシステムの開発などにも対応しています。

組み込みソフトウェア、モバイルアプリ、Windowsアプリ、Webシステムなど、ソフトウェア開発に関するご相談がございましたら、お気軽にお問い合わせください。

また、ニューラルでは一緒にソフトウェア開発に取り組んでいただける技術者の方も募集しています。
ご興味がございましたら、お気軽にお問い合わせください。

EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688

目次へ