2017-06-30 8 views
1

ハフマンコーディングプロトタイプの作成に興味があります。そのために、入力を構成する文字のヒストグラムを作成することから始めます。Java String私は、SOおよび他の場所で多くのソリューション(例を見てきました:。hereStreamのためcollect()方法を使用してだけでなく、非常に具体的かつ直感的な方法でFunction.identity()Collectors.counting()の静的な輸入に依存IntStreamのヒストグラムマップを作成するとコンパイル時エラーが発生する

をただし、使用している場合Iは上記にリンクされたものと不気味なコードの断片は:

private List<HuffmanTrieNode> getCharsAndFreqs(String s){ 
     Map<Character, Long> freqs = s.chars().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 
     return null; 
} 

Iは、本質的に、必要に応じて、Supplierタイプに準拠collectに引数が存在しないことを私に告げるのIntelliJからコンパイル時エラーを受け取りますその署名によって:

Intellij's error message

残念ながら、私は、Java 8 Stream階層に新たなんだと私は私のために最善の行動がどうあるべきか全くわかりません。実際には、Mapの方法は、私がしようとしていることに対してあまりにも多くの定型文句であるかもしれません。もしそうなら、助言してください。

答えて

3

問題はs.chars()IntStream返すことである - Streamの特定の専門と、それは単一の引数を取りcollectを有していません。それはcollect 3引数を取る。明らかにboxedを使用すると、IntStreamStream<Integer>に変換します。

Map<Integer, Long> map = yourString.codePoints() 
      .boxed() 
      .collect(Collectors.groupingBy(
         Function.identity(), 
         Collectors.counting())); 

しかし、今の問題は、あなたがcode-pointsではなく文字をカウントしていることです。文字列がBMPの文字であることが絶対にわかっている場合は、もう1つの答えに示すように、安全にcharにキャストできます。あなたがいないなら、物事がより厄介になる。

この場合、ユニコードコードポイントを文字として取得する必要がありますが、は2バイトのJava charには入りません。ユニコード文字は最大4バイトです。

この場合、マップはMap<String, Long>で、Map<Character, Long>ではありません。サポート\X(およびScanner#findAll)の導入を持つJava-9で

これが行うことは非常に簡単です:javaの-8で

String sample = "A" + "\uD835\uDD0A" + "B" + "C"; 
     Map<String, Long> map = scan.findAll("\\X") 
       .map(MatchResult::group) 
       .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 


System.out.println(map); // {A=1, B=1, C=1, =1} 

これは少しより冗長になります:

String sample = "AA" + "\uD835\uDD0A" + "B" + "C"; 
    Map<String, Long> map = new HashMap<>(); 

    Pattern p = Pattern.compile("\\P{M}\\p{M}*+"); 
    Matcher m = p.matcher(sample); 

    while (m.find()) { 
     map.merge(m.group(), 1L, Long::sum); 
    } 
    System.out.println(map); // {A=2, B=1, C=1, =1} 
+1

' codePoints() 'によって生成されたストリームが' char'sの代わりにコードポイントをカウントするという事実が問題であれば、 'chars()'をOPはそうです。自分で作成した問題を回避しようとしています。 – Holger

+0

@Holger hmm ..あなたは正しいかもしれません。 "人間が読める人物"と何回繰り返したのかを知りたければ、単純に 's.codePoints()。mapToObj(x - > new String(Character.toChars(x))) – Eugene

+3

「人間が判読できる文字」は別のものです。 '' char ''があります。これらの16ビット単位は、1:1または2:1を*コードポイント*にマップすることができますが、(人間が判読可能な)*文字*は、 'U + 0041 U + 0308'、どちらも* BMP内*なので、 "charとvs code point"の問題を "code point vs character(またはgrapheme cluster)"の問題と混同しないことが重要です。最後の2つの例は*文字*に分割されていますが、そのワームの缶を開くには、どの文字が同じかを理解していないことに注意する必要があります。 'U + 0041 U + 0308'は' U + 00C4'と同じです... – Holger

1

String.chars()メソッドは、IntStreamを返します。すでに指摘したように、あなたは、オブジェクト型にプリミティブ型にストリームを変換することができ

s.chars().mapToObj(c -> (char)c) 
+1

コードポイントをcharにキャストすると、 'BMP'のためにのみ動作する – Eugene

0

:あなたはおそらく経由Stream<Character>に変換します。

s.chars().boxed() 
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 
関連する問題