2017-06-06 5 views
2

質問:カンマを含む文字列を完了し、ドットは整数を分離

を考えると、我々はに変換する必要があり、「1,2,3..6..8,9..11」のように入力文字列"1,2,3,4,5,6,7,8,9,10,11"。だから、基本的にはドットで囲まれた範囲に値を設定する必要があります。以下は私の解決策です。これを解決する良い方法がありますか?これをさらに最適化できますか?

public class FlattenAString { 

    public static String flattenAString(String input) { 
     StringBuilder sbr = new StringBuilder(""); 
     StringBuilder current = new StringBuilder(""); 
     StringBuilder next = new StringBuilder(""); 
     int i = 0; 
     while (i < input.length()) { 
      if (input.charAt(i) == '.') { 
       i = i + 2; 
       while (i != input.length() && input.charAt(i) != '.' && input.charAt(i) != ',') { 
        next.append(input.charAt(i)); 
        i++; 
       } 
       int currentInt = Integer.parseInt(current.toString()); 
       int nextInt = Integer.parseInt(next.toString()); 
       appendFromCurrentTillPrevToNextInt(currentInt, nextInt, sbr); 
       current = next; 
       next = new StringBuilder(""); 
      } else if (input.charAt(i) == ',') { 
       sbr.append(current); 
       sbr.append(','); 
       current = new StringBuilder(""); 
       i++; 
      } else { 
       current.append(input.charAt(i)); 
       i++; 
      } 
     } 
     sbr.append(current); 
     return sbr.toString(); 
    } 

    private static void appendFromCurrentTillPrevToNextInt(int current, int val, StringBuilder sbr) { 
     for (int i = current; i < val; i++) { 
      sbr.append(i); 
      sbr.append(','); 
     } 
    } 
} 
+0

コードレビュー(https://codereview.stackexchange.com)には良い質問のようです。 –

+0

'[1..n]'のすべての数字があると、最初の数字と最後の数字だけを取り、それらの間の他の数字をすべて記入できません。 – Oswald

+0

@Oswald:実際には整数がない場合の最適な解決策です。ありがとう –

答えて

0

入力文字列を2度に分割することでこれにアプローチします。まずカンマで区切って、単一の数字または省略記号の範囲を取得します。単一の数字の場合は、単にリストに追加するだけです。範囲については、..で2番目の分割を行い、別の番号のリストを取得してください。次に、これらのペアのそれぞれの範囲を反復処理して、欠損値を埋めます。

ここで1つのトリッキーな点は、範囲内の数値の位置を二重にカウントすることを避ける必要があることです。これは、最良の例で説明されています

この範囲については
3..6..8 

、我々は最初の3, 4, 5, 6を追加します。しかし、2番目の省略記号については、で始まり、8に達するまで続きます。

String input = "1,2,3..6..8,9..11"; 
String[] parts = input.split(","); 
List<Integer> list = new ArrayList<>(); 

for (String part : parts) { 
    if (!part.contains("..")) { 
     list.add(Integer.parseInt(part)); 
    } 
    else { 
     String[] ranges = part.split("\\.\\."); 
     for (int i=0; i < ranges.length-1; ++i) { 
      int start = Integer.parseInt(ranges[i]) + (i == 0 ? 0 : 1); 
      int end = Integer.parseInt(ranges[i+1]); 
      for (int j=start; j <= end; ++j) list.add(j); 
     } 
    } 
} 

// print list of numbers 
for (int i=0; i < list.size(); ++i) { 
    System.out.print((i > 0 ? ", " : "") + list.get(i)); 
} 

出力:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 

ここにデモ:

Rextester

+0

あなたのソリューションが空間の複雑さを増すとは思わない?あなたはトークンを保持するための配列(部分)を取っているからです。 –

+0

はい、配列はスペースを取るが、あなたのアプローチもこれを行うように見えます。私のアプローチが使用するスペースは、入力文字列のサイズ/最終範囲の数値の数に比例します。いずれにしても、 'String#split()'を利用することで、全体的な問題の複雑さが大幅に軽減され、少しのスペースを使っても問題はありません。 –

+0

文字列のサイズが非常に大きい場合はどうなりますか?あなたはまだn個のオブジェクトを一度にメモリに保持していますか?私のソリューションは、一度にメモリに余分なスペースを保持していない、それはStringBuilderを出力するためにデータをフラッシュしているバッファのように動作しています。 –

0

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

static final Pattern RANGE = Pattern.compile("(\\d+)(\\.\\.(\\d+))+"); 

static String flattenString(String input) { 
    StringBuffer sb = new StringBuffer(); 
    StringBuilder temp = new StringBuilder(); 
    Matcher m = RANGE.matcher(input); 
    while (m.find()) { 
     int begin = Integer.parseInt(m.group(1)); 
     int end = Integer.parseInt(m.group(3)); 
     temp.setLength(0); 
     for (int i = begin; i <= end; ++i) 
      temp.append(",").append(i); 
     m.appendReplacement(sb, temp.substring(1)); 
    } 
    m.appendTail(sb); 
    return sb.toString(); 
} 
関連する問題