4

文字列を 1 文字ずつ処理し、それを解析してツリーのような構造を作成する再帰アルゴリズムがあります。パーサーが現在いる文字インデックスを追跡できるようにしたいのですが (他の何よりもエラーメッセージについて)、複数の返された型を処理するタプルのようなものを実装することに熱心ではありません。

メソッドの外側で宣言され、再帰メソッドに渡された Integer 型を使用しようとしましたが、それは最終的なものであるため、戻ったときに再帰呼び出しのインクリメントは「忘れられます」。(整数値の増分により、値渡しオブジェクトの参照ポイントが新しいオブジェクトになるため)

私のコードを汚染しないような仕事に似たものを得る方法はありますか?

4

8 に答える 8

2

疑似可変整数「ハック」をすでに発見しているので、次のオプションはどうですか。

別の Parser クラスを作成することは理にかなっていますか? これを行うと、メンバー変数に現在の状態を格納できます。おそらく、スレッド セーフの問題をどのように処理するかを考える必要があり、この特定のアプリケーションではやり過ぎかもしれませんが、うまくいく可能性があります。

于 2008-08-29T16:52:37.917 に答える
2

これはハックのようなものですが、可変の AtomicInteger を使用して、このようなことを行うことがあります。サイズ 1 の int[] が渡されるケースも見てきました。

于 2008-08-29T16:40:44.903 に答える
2

私が使用している現在のソリューションは次のとおりです。

int[] counter = {0};

それを再帰アルゴリズムに渡します。

public List<Thing> doIt (String aString, int[] counter) { ... }

そして、それを増やしたいとき:

counter[0]++;

超エレガントではありませんが、機能します...

于 2008-08-29T16:44:06.267 に答える
2

整数は不変です。つまり、整数を引数として渡すと、同じアイテムへの参照ではなくコピーが作成されます。(説明)。

探している動作を取得するには、Integer only mutable のような独自のクラスを作成できます。次に、再帰関数に渡すだけで、再帰内でインクリメントされ、再帰が終了した後に再度アクセスすると、新しい値が維持されます。

編集: int[] 配列の使用は、このメソッドのバリエーションであることに注意してください... Java では、配列は、プリミティブや不変クラスのようにコピーされるのではなく、参照によって渡されます。

于 2008-08-29T16:47:59.440 に答える
1

次のこともできます。

private int recurse (int i) {

    if (someConditionkeepOnGoing) {
        i = recurse(i+1);
    }

    return i;
}
于 2012-03-06T16:47:23.727 に答える
1

doIt メソッドが呼び出されるたびにインクリメントされる静的 int クラス変数を使用できます。

于 2008-08-29T18:05:34.933 に答える
0

私が考えることができる 1 つの可能性は、カウントをクラスのメンバー変数に格納することです。もちろん、これは publicdoItメソッドが単一のスレッドによってのみ呼び出されることを前提としています。

もう 1 つのオプションは、パブリック メソッドをリファクタリングして、プライベート ヘルパー メソッドを呼び出すことです。プライベート メソッドは、リストをパラメーターとして受け取り、カウントを返します。例えば:

public List<Thing> doIt(String aString) {
    List<Thing> list = new ArrayList<Thing>();
    int count = doItHelper(aString, list, 0);
    // ...
    return list;
}

private int doItHelper(String aString, List<Thing> list, int count) {
    // ...
    // do something that updates count
    count = doItHelper(aString, list, count);
    // ...
    return count;
}

これは、変数が実際には呼び出し元に返されないdoItため、パブリック メソッドでエラー処理を実行できることを前提としています。countそれを行う必要がある場合は、もちろん例外をスローできます。

public List<Thing> doIt(String aString) throws SomeCustomException {
    List<Thing> list = new ArrayList<Thing>();
    int count = doItHelper(aString, list, 0);
    // ...
    if (someErrorOccurred) {
        throw new SomeCustomException("Error occurred at chracter index " + count, count);
    }
    return list;
}

アルゴリズムが実際にどのように機能するかを詳しく知らずに、それが役立つかどうかを知ることは困難です。

于 2008-08-29T17:51:32.767 に答える
0

正直なところ、関数を再コーディングして、ループを使用する線形アルゴリズムにします。このようにして、非常に大きな文字列をステップ実行している場合でも、ヒープ スペースが不足する可能性はありません。また、カウントを追跡するためだけに追加のパラメーターを用意する必要はありません。

これにより、すべての文字に対して関数呼び出しを行う必要がないため、アルゴリズムが高速化される可能性があります。

もちろん、特別な理由がない限り、再帰的である必要があります。

于 2008-08-29T16:59:16.073 に答える