yucatio@システムエンジニア

趣味で作ったものいろいろ

頭の体操[初級] 連続したフィールドの入力で、途中の未入力欄を検知 (Java編)

以前に、仕事で以下のような挙動をする処理を書く必要がありました(正確には、後輩が実装して自分はレビュー担当)。連続して値を入れるような入力欄で、途中で入力が空になっている場所を検知します。

f:id:yucatio:20160723111152p:plain

実装してみよう

サンプルとして、以下のようなメソッドを作成します。

  • 引数にStringの配列を受け取る
  • 配列の途中に空文字があり、その欄より後に空文字でない要素がある場合は、エラーメッセージを表示する。メッセージ中には何番目の要素がエラーかを表示する。

こんな動作イメージです

detectEmptyField02(new String[]{"佐藤", "鈴木", "高橋", "", "伊藤", "", "", "", "", ""});

// OUTPUT
// 4番目のフィールドが空です。値を入力してください。

簡単のために、以下を前提とします。

  • 引数で渡される配列はnullではない
  • 配列中の各要素はnullでない

自分の勉強のためにも、JavaRuby両方で実装してみます。この記事ではJavaで実装します。

実装は続きを読むをどうぞ

実装 その1

実装方針 その1

配列の各要素について、その要素が空文字かつ後方に空文字でない要素がある場合はエラーメッセージを出力します。

f:id:yucatio:20160723130648p:plain

public void detectEmptyField(String[] arr) {
  for (配列の各要素) {
    if (要素が空文字) {
      if (配列の後方に空文字でない要素がある) {
        "n番目の要素が空です" の出力
      }
    }
  }
}

実装 その1

実装するとこんな感じですね。ネストが深い。

public void detectEmptyField(String[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
    if ("".equals(arr[i])) {
      for (int j = i + 1; j < arr.length; j++) {
        if (!"".equals(arr[j])) {
          System.out.println((i+1) + "番目のフィールドが空です。値を入力してください。");
          break;
        }
      }
    }
  }
}

実装 その2

実装方針 その2

実装方針その1では、配列を先頭から見ていきました。要素が空文字かつ配列の後方に空文字でない要素があればエラーとしました。 この方法でも正しく動作するのですが、同じ要素を何度も参照するのは効率悪いなと思ったので、別の方法を考えます。

配列を後ろから見ていって、初めに空でない要素が現れたときに、その配列のインデックスを保存しておきます。 そのあと、配列を前から見ていって、空文字であればエラーとします。

f:id:yucatio:20160723130654p:plain

public void setectEmptyField(String[] arr) {
  for (配列の各要素を後方からループ) {
    if (空でない要素) {
      配列のインデックスを保存;
      break;
    }
  }

  for (配列の初めから保存したインデックスの各要素) {
    if (空文字) {
         "n番目の要素が空です" の出力
     }
  }
}

実装 その2

実装するとこんな感じ。

public void setectEmptyField(String[] arr) {
  int lastNonEmptyIndex = -1;
  for (int i=arr.length-1; i>=0; i--) {
    if (! "".equals(arr[i])) {
      lastNonEmptyIndex = i;
      break;
    }
  }
  
  for (int i=0; i < lastNonEmptyIndex; i++) {
    if ("".equals(arr[i])) {
      System.out.println((i+1) + "番目のフィールドが空です。値を入力してください。");
    }
  }
}

動作確認

コメントで出力結果を書いていきます。

public static void main(String[] args) {
  DetectEmptyFiledSample01 sample = new DetectEmptyFiledSample01();
  sample.detectEmptyField02(new String[]{"佐藤", "鈴木", "高橋", "田中", "伊藤", "渡辺", "山本", "中村", "小林", "加藤"});
  // (出力なし)
  
  sample.detectEmptyField02(new String[]{"佐藤", "鈴木", "高橋", "田中", "", "", "", "", "", ""});
  // (出力なし)

  sample.detectEmptyField02(new String[]{"佐藤", "", "", "", "", "", "", "", "", ""});
  // (出力なし)

  sample.detectEmptyField02(new String[]{"", "", "", "", "", "", "", "", "", ""});
  // (出力なし)

  sample.detectEmptyField02(new String[]{"佐藤", "鈴木", "高橋", "田中", "", "", "山本", "中村", "", ""});
  // 5番目のフィールドが空です。値を入力してください。
  // 6番目のフィールドが空です。値を入力してください。

  sample.detectEmptyField02(new String[]{"", "", "高橋", "田中", "", "", "山本", "中村", "", ""});
  // 1番目のフィールドが空です。値を入力してください。
  // 2番目のフィールドが空です。値を入力してください。
  // 5番目のフィールドが空です。値を入力してください。
  // 6番目のフィールドが空です。値を入力してください。
  
  sample.detectEmptyField02(new String[]{"", "", "", "", "", "", "", "", "", "加藤"});
  // 1番目のフィールドが空です。値を入力してください。
  // 2番目のフィールドが空です。値を入力してください。
  // 3番目のフィールドが空です。値を入力してください。
  // 4番目のフィールドが空です。値を入力してください。
  // 5番目のフィールドが空です。値を入力してください。
  // 6番目のフィールドが空です。値を入力してください。
  // 7番目のフィールドが空です。値を入力してください。
  // 8番目のフィールドが空です。値を入力してください。
  // 9番目のフィールドが空です。値を入力してください。
}

うまく行きましたね。

補足

補足1

どちらの実装がよいか迷いましたが、仕事では2番目の方法を採用しました。実行速度は、要素の数が多ければ方法2の方が速いですが、要素数が数10の時はあまり変わらないと思います。

補足2

ユーザの入力に未入力欄があった場合は、システム側で前に詰めればよいとも思ったのですが、ユーザ側で間違って途中の欄を消してしまった可能性を考えてこのような仕様になりました。

こちらもどうぞ

Ruby編です

yucatio.hatenablog.com