配列トラバーサルについては、基本的にすべての開発者がそれについて書いています。トラバーサル自体については特に言うことはありませんが、トラバーサル プロセス中に複雑なビジネス ロジックがある場合、次のことがわかります。コードのレベルは徐々に深くなります。
たとえば、単純なケースでは、2 次元配列から偶数を見つけてリストに保存します。
2 次元を横断します。配列して各要素を判定する 偶数かどうかを簡単に書くことができます。 例えば:
public void getEven() { int[][] cells = new int[][]{{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; List<Integer> ans = new ArrayList<>(); for (int i = 0; i < cells.length; i ++) { for (int j = 0; j < cells[0].length; j++) { if ((cells[i][j] & 1) == 0) { ans.add(cells[i][j]); } } } System.out.println(ans); }
上記の実装でも問題ありませんが、このコードの深さは簡単に記述できます。 3レベル; 上記の場合 if 他に判定条件があれば簡単にコードレベルを上げることができる; 2次元配列でも良いが、3次元配列だと1回の走査が3レベルになる; ちょっとした工夫で論理的には、4 つまたは 5 つのレベルは数分で達成できますよね?
それでは、問題は、コード レベルが上がるとどのような問題が発生するかということです。
コードが実行できる限り、問題は何でしょうか? !
多次元配列の走査レベルは当然ながら非常に深いため、それを削減する方法はあるのでしょうか?
この問題を解決するには、要点を押さえることが重要ですが、横断の要点は何でしょうか?各要素の座標を取得しましょう!では、何ができるでしょうか?
関数メソッドを定義し、入力は関数座標であり、この関数本体でトラバーサル ロジックを実行します。
上記の考えに基づいて、簡単にできると思います。 2 次元配列トラバーサルの一般的なメソッドを書くのは簡単です
public static void scan(int maxX, int maxY, BiConsumer<Integer, Integer> consumer) { for (int i = 0; i < maxX; i++) { for (int j = 0; j < maxY; j++) { consumer.accept(i, j); } } }
主な実装は上記です。関数メソッドはデフォルトで JDK が提供する BiConsumer を直接使用します。渡される 2 つのパラメータは、次のように両方とも int 配列です。下の表; 戻り値なし
それでは、上記をどのように使用するのでしょうか?
上記の例と同じですが、変更後は次のようになります:
public void getEven() { int[][] cells = new int[][]{{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; List<Integer> ans = new ArrayList<>(); scan(cells.length, cells[0].length, (i, j) -> { if ((cells[i][j] & 1) == 0) { ans.add(cells[i][j]); } }); System.out.println(ans); }
前と比べると、レイヤーが 1 つだけ減っているように見えますが、
ただし、配列が 3 次元、4 次元、または無次元になっても、この変更の書き込みレベルは変わりません。
Previous 通常のトラバーサル実装では問題ないのですが、トラバーサル処理中に何らかの条件が発生して直接リターンした場合、サポートできるのでしょうか?
たとえば、2 次元配列を走査していて、その中に偶数が含まれているかどうかを判断したい場合、どうすれば四捨五入できるでしょうか?
リターンをサポートできるように、スキャン メソッドについて慎重に考えてください。主な問題は、関数メソッドの実行後、ループを続行するか直接リターンするかをどうやって判断すればよいかということです。
それは簡単です。思い浮かぶのは、実行ロジックに追加の戻り値を追加して、ループを中断して直接戻るかどうかをマークすることです。
このアイデアに基づいて、簡単なデモ バージョンを実装できます
定義ループの添字戻り値を受け入れる function メソッド
@FunctionalInterface public interface ScanProcess<T> { ImmutablePair<Boolean, T> accept(int i, int j); }
一般的なループ メソッドは、それに応じて変更できます。
public static <T> T scanReturn(int x, int y, ScanProcess<T> func) { for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { ImmutablePair<Boolean, T> ans = func.accept(i, j); if (ans != null && ans.left) { return ans.right; } } } return null; }
上記の考えに基づいて、私たちの実際の使用姿勢は次のとおりです:
@Test public void getEven() { int[][] cells = new int[][]{{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; List<Integer> ans = new ArrayList<>(); scanReturn(cells.length, cells[0].length, (i, j) -> { if ((cells[i][j] & 1) == 0) { return ImmutablePair.of(true, i + "_" + j); } return ImmutablePair.of(false, null); }); System.out.println(ans); }
上記の実装は私たちのニーズを満たすことができます。唯一厄介なのはリターンです。これは常に少しエレガントではありません。このメソッドの他に、他のメソッドもあります。方法?
戻り値について考えたので、パラメーターを渡す場合はどうすればよいでしょうか?定義されたパラメータを使用して、中断して結果を返すかどうかを決定することは可能ですか?
このアイデアに基づいて、最初にパラメーター パッケージング クラスを定義できます。
public static class Ans<T> { private T ans; private boolean tag = false; public Ans<T> setAns(T ans) { tag = true; this.ans = ans; return this; } public T getAns() { return ans; } } public interface ScanFunc<T> { void accept(int i, int j, Ans<T> ans) }
Ans クラスを通じてループ結果を記録したいと考えています。ここで、tag=true は意味します。ループを続ける必要はありません。ans 結果を直接返すだけです。
対応するメソッド変換と例は次のとおりです。
public static <T> T scanReturn(int x, int y, ScanFunc<T> func) { Ans<T> ans = new Ans<>(); for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { func.accept(i, j, ans); if (ans.tag) { return ans.ans; } } } return null; } public void getEven() { int[][] cells = new int[][]{{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; String ans = scanReturn(cells.length, cells[0].length, (i, j, a) -> { if ((cells[i][j] & 1) == 0) { a.setAns(i + "_" + j); } }); System.out.println(ans); }
これは、前のものよりも見栄えが良くなります。 one
実際に実行して、出力が期待と一致するかどうかを確認します。
##
以上がJava で関数を使用して 2 次元配列を走査するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。