0

我慢してください。私は 1 年以上プログラミングをしていませんが、現在、「宿題の質問」をして、就職の面接のために自分の Java を見直しています。私の関数は、指定された文字列のすべての文字を含む文字列を返すことになっています。これを行うためのより厄介な方法はありますか?

public String stringBits(String str) {
  StringBuffer tmp = new StringBuffer();
  for(int i = 0; i<str.length(); i+=2)
    tmp.append(str.charAt(i));
  String ret = new String(tmp);
  return ret;
4

7 に答える 7

3

StringBuilderではなくを使用しますStringBuffer。はマルチスレッドの状況向けであり、同期しないStringBufferため よりも遅くなります。StringBuilderこのスレッドのさまざまな回答でリストされている、これを行うための 4 つの基本的な方法をテストしました。ただし、ここで私がいつも行っている特定の事柄に注意してください。面接担当者が本当に求めているものは次のとおりです。

  • String += nextCharacter;を使用するよりもはるかに遅いので、私は決して使用しませんStringBuilder
  • を設定したinitialCapacity方が常に速いためです。そうしないと、StringBuilderいっぱいになると、新しい配列を再割り当てしてコピーする必要がありますが、これは遅くなります。

そしてコード:

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Random;

public class EveryOtherTest {
    public static class StringBenchmark extends SimpleBenchmark {
        private String input;

        protected void setUp() {
            Random r = new Random();
            int length = r.nextInt(1000) + 1000;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++) {
                sb.append((char) ('A' + r.nextInt(26)));
            }
            input = sb.toString();
        }

        public String timeCharArrayForeach(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
                boolean use = false;
                for (char c : input.toCharArray()) {
                    if(use) sb.append(c);
                    use = !use;
                }
                String newOutput = sb.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeCharArrayPlusTwo(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
                char[] charArray = input.toCharArray();
                for(int j = 0; j < input.length(); j += 2) {
                    sb.append(charArray[j]);
                }
                String newOutput = sb.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeCharAt(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder tmp = new StringBuilder(input.length() / 2 + 1);
                for (int j = 0; j < input.length(); j += 2) {
                    tmp.append(input.charAt(j));
                }
                String newOutput = tmp.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeIterator(int reps) {
            String output = "";
            Random r  = new Random();
            for(int i = 0; i < reps; i++) {
                StringBuilder buf = new StringBuilder(input.length() / 2 + 1);
                StringCharacterIterator iterator = new StringCharacterIterator(input);
                for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
                    buf.append(c);
                    iterator.next();
                }
                String newOutput = buf.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeRegex(int reps) {
            String output = "";
            Random r  = new Random();
            for(int i = 0; i < reps; i++) {
                String newOutput = input.replaceAll("(?<!^).(.)", "$1");
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }
    }

    public static void main(String... args) {
        Runner.main(StringBenchmark.class, args);
    }
}

結果:

 0% Scenario{vm=java, trial=0, benchmark=CharArrayForeach} 2805.55 ns; ?=688.96 ns @ 10 trials
20% Scenario{vm=java, trial=0, benchmark=CharArrayPlusTwo} 3428.48 ns; ?=475.32 ns @ 10 trials
40% Scenario{vm=java, trial=0, benchmark=CharAt} 2138.68 ns; ?=379.44 ns @ 10 trials
60% Scenario{vm=java, trial=0, benchmark=Iterator} 3963.94 ns; ?=389.53 ns @ 10 trials
80% Scenario{vm=java, trial=0, benchmark=Regex} 58743.66 ns; ?=10850.33 ns @ 10 trials

       benchmark    us linear runtime
CharArrayForeach  2.81 =
CharArrayPlusTwo  3.43 =
          CharAt  2.14 =
        Iterator  3.96 ==
           Regex 58.74 ==============================

vm: java
trial: 0
于 2013-07-18T22:22:45.820 に答える
2

イテレータ アプローチを好む場合は、StringCharacterIteratorクラスがあります。

于 2013-07-18T22:15:23.383 に答える
1

この正規表現に相当するものを使用できます

String newString = str.replaceAll("(?<!^).(.)", "$1");
于 2013-07-18T22:26:56.750 に答える
0

いいえ、これはまったく厄介なことではありません。有用なタスクごとに、より適切な方法があるかもしれませんが、この場合、文字列を反復処理するしかありません。

于 2013-07-18T22:16:42.660 に答える
0

これもうまくいくはずで、私にはもっとシンプルに見えます。

public String stringBits(String str) {
    String tmp = "";
    for(int i = 0; i<str.length(); i+=2)
        tmp+=str.charAt(i);
    return tmp;

2 番目、4 番目、6 番目、... の文字が必要な場合は、i が 1 になるように編集します。

于 2013-07-18T22:19:26.607 に答える
0

文字列を CharArray に変換し、for-each ループを使用できます。

for (char c: str.toCharArray()){
}

もちろん、他のすべてのキャラクターを取得するには、おそらくカウンターまたはフラグが必要になるため、それほど厄介ではありません.

于 2013-07-18T22:20:24.000 に答える
0

あなたがしていることは、私が知る限り機能します。簡単なテストケースを次に示します。

package com.sandbox;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SandboxTest {

    @Test
    public void testMocking() {
        assertEquals("foo", stringBits("f1o2o3"));
    }

    public String stringBits(String str) {
        StringBuffer tmp = new StringBuffer();
        for (int i = 0; i < str.length(); i += 2) {
            tmp.append(str.charAt(i));
        }
        String ret = new String(tmp);
        return ret;
    }
}

かなり真っ直ぐな方法だと思います。おそらく正規表現とグループを使用してそれを行う方法がありますが、現在のコードの方が読みやすいと感じています。


@Joeyの回答を見るまで聞いたことがありませんでしたがStringCharacterIterator、興味深い解決策のようです。彼の答えを使用したコードは次のとおりです。

package com.sandbox;

import org.junit.Test;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;

import static org.junit.Assert.assertEquals;

public class SandboxTest {

    @Test
    public void testMocking() {
        assertEquals("foo", stringBits("f1o2o3"));
    }

    public String stringBits(String str) {
        StringBuilder buf = new StringBuilder();
        StringCharacterIterator iterator = new StringCharacterIterator(str);
        for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
            buf.append(c);
            iterator.next();
        }
        return buf.toString();
    }
}
于 2013-07-18T22:21:03.353 に答える