2009-05-21 20 views
2

ここにその方法があります。私はここでベストプラクティスに違反しているのか、それとも言語に関しては何か間違っていることを知りたいのです。このメソッドを最適化して文字列を分割する方法を教えてください。

private List<String> breakStringInChunks(String text, int chunkSize) { 
     List<String> chunks = new ArrayList<String>(); 
     String temporary = ""; 
     int numberOfChunks = text.length()/chunkSize; 
     int beginIndex = 0; 
     int endIndex = 0; 

     // Add one iteration if numberOfChunks*chunkSize is less than the length of text. 
     if ((numberOfChunks * chunkSize) < text.length()) { 
      numberOfChunks++; 
     } 

     // Cut strings and add in the list. 
     for (int i = 0; i < numberOfChunks; i++) { 
      endIndex+=chunkSize; 
      if ((i + 1) == numberOfChunks) { 
       temporary = text.substring(beginIndex); 
      } 
      else { 
       temporary = text.substring(beginIndex, endIndex); 
      } 
      beginIndex=endIndex; 
      chunks.add(temporary); 
     } 

     return chunks; 
    } 
+1

なぜ、文字列をチャンク化するのですか? –

答えて

4

簡潔、そして得られたリストの潜在的なサイズ変更を避ける:

はこれを試してみてください。ここで

private static List<String> breakStringInChunks(final String text, final int chunkSize) { 
    final int numChunks = 0 == (text.length() % chunkSize) ? text.length()/chunkSize : 1 + (text.length()/chunkSize); 
    final List<String> chunks = new ArrayList<String>(numChunks); 
    for (int startIndex = 0; startIndex < text.length(); startIndex += chunkSize) { 
     final int endIndex = Math.min(text.length(), startIndex + chunkSize); 
     chunks.add(text.substring(startIndex, endIndex)); 
    } 
    return chunks; 
} 
+0

ニック、これは素晴らしい解決策です。 – Joset

+1

実際、私はニックの元々の解答に対するコメント投稿者です。彼がすでに私のコメントを見たことに気づく前に、私は外に出て自分の解決策を修正しました。 –

+0

クールハンク。ありがとう。 – Joset

1

それは少し冗長だし、ガベージコレクションが少し遅くさせる可能性がある、あなたの方法の開始時にtemporary文字列を宣言する必要はありません。簡潔になり、次の

private List<String> breakStringInChunks(String text, int chunkSize) { 
    int nChunks = (int)Math.ceil(((double)text.length())/chunkSize)); 
    List<String> chunks = new ArrayList<String>(nChunks); 
    // Cut strings and add in the list. 
    for (int i = 0; i < text.length(); i+=chunkSize) { 
     int endIndex=i+chunksize; 
     if (endIndex >= text.length()) { 
      chunks.add(text.substring(i)); 
     } else { 
      chunks.add(text.substring(i, endIndex)); 
     } 
    } 
    return chunks; 
} 

あなたの方法と上記のテキストについての一つの良いところは、常に元の文字列に()部分文字列を呼び出すので、それが保存されますので、Javaは唯一、元の文字列を参照するということですいくつかのメモリ割り当て。

私は} else {がJavaのより一般的なコーディング標準だと思います。

+1

チャンクがたくさんある場合は、わかっているinitialCapacityをArrayListに割り当てると意味があります(例:final List chunks = new ArrayList (1 +(text.length()/ chunkSize))。 –

+1

が合意しました。私は編集します。厳密に言えば、私はそれがceilでなければならないと思います。 –

+0

forループではi ++よりもchunkSizeでなければなりません。そうでなければ、文字列の各文字に対して1つのチャンクがあります。私はbeginIndex変数が必要ではないことに同意します。 –

1

私はあなたの意図を誤解している場合を除き、文字列が不変であるためアルゴリズムが非常に非効率的になるように、文字列の作成をかなり頻繁に使用します。まだ

public List<String> breakStringsInChunks(String text,int chunkSize) { 
    if (chunkSize<=1) { 
     throw new IllegalArgumentException("Chunk size must be positive"); 
    } 
    if (text==null || text.isEmpty()) { 
     return Collections.emptyList(); 
    } 

    List<String> chunks= new LinkedList<String>(); 

    int index=0; 
    int len = text.length(); 

    //guaranteed to succeed at least once since 0 length strings we're taken care of 
    do { 
     chunks.add(text.substring(index, Math.min(index + chunkSize, len))); 
     index+=chunkSize; 
    } while (index<len); 

    return chunks; 
} 
+0

これもいいですね。なぜLinkedList over ArrayListを選択しましたか? – Joset

+0

確かに、/ stringは不変なので、かなり効率的です。 String.substring()は、元のデータを指す新しい文字列をコピーする必要なく返すことができます。また、あなたの答えは部分文字列と同じ数の呼び出しを行います。 –

+0

LinkedListは、作成/追加時にノードのメモリを割り当てることで、大量のメモリ割り当てを回避します(ただし、参照のローカリティが低いために後で読み込みが遅くなる可能性があります)既にそこにあるすべてのものを新しい大きな場所にコピーすることを含むバッキングアレイを拡張する必要があります)。 *一般的に* ArrayListは、割り当てるスペースの大きさや、非常に頻繁にサイズを変更する必要がないことが合理的かどうかを知っている方が良いでしょう。 –

0
public static final List<String> chunk(final String text, final int chunkSize) { 
    // Figure out how many chunks we are going to make. 
    final int textLength = text.length(); 
    final int numberOfChunks = 
     textLength % chunkSize == 0 
     ? textLength/chunkSize 
     : textLength/chunkSize + 1; 

    // Create an array list of just the right size. 
    final ArrayList<String> chunks = new ArrayList<String>(numberOfChunks); 

    // Do all the chunking but the last one - here we know that all chunks 
    // are exactly chunkSize long. 
    for (int i = 0; i < numberOfChunks - 1; i++) { 
     chunks.add(text.substring(i * chunkSize, (i + 1) * chunkSize)); 
    } 

    // Add final chunk, which may be shorter than chunkSize, so we use textLength 
    // as the end index. 
    chunks.add(text.substring((numberOfChunks - 1) * chunkSize, textLength)); 

    return chunks; 
} 
0

私の解決策です。私は非常に効率的にこれを実装しようとしました:

public static List<String> breakStringInChunks(String text, int chunkSize) { 
    if (chunkSize < 2) { 
     throw new IllegalArgumentException("Chunk size must be > 1"); 
    } 
    if (null == text || text.isEmpty()) { 
     return Collections.emptyList(); 
    } 

    List<String> chunks = new ArrayList<String>(1 + (text.length()/chunkSize)); 

    int length = text.length() - (text.length() % chunkSize); 

    for (int i = 0; i < length;) { 
     chunks.add(text.substring(i, i += chunkSize)); 
    } 
    if (length < text.length()) 
     chunks.add(text.substring(length)); 

    return chunks; 
} 
0

どのようにこのような何か?

private List<String> breakStringInChunks(String text, int chunkSize) 
{ 
    List<String> chunks = new ArrayList<String>(); 
    while (text.length() > 0) 
    { 
     if (chunkSize > text.length()) 
     { 
      chunkSize = text.length(); 
     } 
     chunks.add(text.substring(0, chunkSize)); 
     text = text.substring(chunkSize); 
    } 
    return chunks; 
} 
+0

これは、最初のチャンクを繰り返し追加する無限ループをロックし、String.length()は変更されません。実際に元のデータのコピーを実際に実行しているため、比較が非常に遅いと思われるストリームインターフェイスについて考えていると思います。 –

+0

文字列の長さは変更されます*。ループの最後の行は、本質的に "text"変数からすでに処理された文字を削除します。 –

+0

ここでの問題は、引数が変更されていることです。 – Joset

0

ここにあります。他の答えと大きく異なるわけではありませんが、テスト駆動です。

public class ChunkTest extends TestCase { 
    public void testEmpty() throws Exception { 
     assertEquals(0, breakStringInChunks("", 1).size()); 
    } 

    public void testOneChunk() throws Exception { 
     String s = "abc"; 
     List<String> chunks = breakStringInChunks(s, s.length()); 
     assertEquals(s, chunks.get(0)); 
     assertEquals(1, chunks.size()); 
    } 

    public void testPartialChunk() throws Exception { 
     String s = "abc"; 
     List<String> chunks = breakStringInChunks(s, s.length() + 1); 
     assertEquals(s, chunks.get(0)); 
     assertEquals(1, chunks.size()); 
    } 

    public void testTwoChunks() throws Exception { 
     String s = "abc"; 
     List<String> chunks = breakStringInChunks(s, 2); 
     assertEquals("ab", chunks.get(0)); 
     assertEquals("c", chunks.get(1)); 
     assertEquals(2, chunks.size()); 
    } 

    public void testTwoEvenChunks() throws Exception { 
     String s = "abcd"; 
     List<String> chunks = breakStringInChunks(s, 2); 
     assertEquals("ab", chunks.get(0)); 
     assertEquals("cd", chunks.get(1)); 
    } 

    private List<String> breakStringInChunks(String text, int chunkSize) { 
     if (text.isEmpty()) 
      return Collections.emptyList(); 
     int n = (text.length() + chunkSize - 1)/chunkSize; 
     List<String> chunks = new ArrayList<String>(n); 
     for (int i = 0; i < n; ++i) 
      chunks.add(text.substring(i * chunkSize, Math.min((i + 1) * chunkSize, text.length()))); 
     return chunks; 
    } 
}