2017-12-26 15 views
0

テキスト内のすべての文字の頻度を数えて印刷しようとしています。 ArrayまたはArrayListを使用し、キーと値のペアを持つマップは使用しないでください。ストリーム内、マップなし、キーと値のペアを使用せずにテキスト内のチャート周波数をカウントして出力する

以下のコードは好ましい結果を示します。 ループを取り除きたいmain countLetters()のすべての作業を行います。

明確にするには、forループやif文を使用しない機能的な方法でこれを実行したいと思います。 これはできますか?そしてもしそうなら、どうですか?

 
public class LetterCounter4 {

public static void main(String[] a) { System.out.print("Input text > "); int[] res = countLetters(); for (int i = 0; i < res.length; i++) { if(res[i] != 0){ System.out.println((char) ('a' + i) + " appears " + res[i] + ((res[i] == 1 ? " time" : " times"))); } } } private static int[] countLetters() { return Arrays.stream(new Scanner(System.in).nextLine().toLowerCase() .split("")) .map(s -> s.charAt(0)) .filter(Character::isLetter) .collect(Collector.of( () -> new ArrayList<Integer>(Collections.nCopies(26, 0)), (li, el) -> { Integer oInt = li.get(el - 'a'); li.set(el - 'a', ++oInt); }, (result1, result2) -> { for (int i = 0; i < result1.size(); i++) { Integer temp = result1.get(i); result1.set(i, temp + result2.get(i)); } return result1; })) .stream() .mapToInt(Integer::intValue) .toArray(); } }

+0

そして、それだけでなし、リストの値を印刷しますか?しかし、私はすべての値を対応する文字にリンクすることはできません。私が各ステップで印刷しているリストのインデックスを知ることができた場合を除きます。 – xtra

答えて

1

を求めているものであるサンプルコードの希望です。誰かがÀまたは[a-zA-Z]範囲外の他の文字を入力すると、コードは簡単になり、爆発しません。しかし、それはMapを作成します。これはあなたが望んでいないと言います。

あなたが特に配列やリストに固執したい場合は、ここでそれを行う方法です:

public static void main(String[] args) { 
    String input = new Scanner(System.in).nextLine(); 

    int[] counts = countLetters(input); 

    IntStream.range(0, counts.length) 
      .filter(i -> counts[i] > 0) 
      .forEachOrdered(i -> System.out.printf("%c appears %s %s%n", 
        'a' + i, 
        counts[i], 
        counts[i] > 1 ? "times" : "time" 
      )); 
} 

public static int[] countLetters(String s) { 
    return s.chars() // this is better than stream(split("")) 
      .filter(Character::isLetter) // WRONG to assume that all letters are [a-zA-Z] 
      .map(chr -> Character.toLowerCase(chr) - 'a') 
      .collect(
        () -> new int[26], 
        (ary, i) -> ary[i]++, 
        (a,b) -> Arrays.setAll(a, i -> a[i] + b[i]) 
      ); 
} 
+0

これは確かに私が探していたものです。 collectのためのコンバイナは、(a、b)→{(int i = 0; i a [i] + = b [i]を渡します。どうしてあなたはint iをパラメータとして渡すだけで、i、a、bではないのですか?私は3つのパラメータを求める機能的なインタフェースが必要だった。配列を知るためには、それを操作する必要があります。 – xtra

+1

@xtra申し訳ありませんが、それはタイプミスでした(コードはまだ動作しますが)。 'i - > a [i] + b [i]'と読みます。 'i'は明示的に渡されます。 'a'と' b'は囲みスコープから取り込まれます。 – Misha

+0

"すべての文字が[a-zA-Z]であると仮定すると間違っている"と言うときは、長さが26の固定長の配列に集めて同じミスをしてはいけません... "[a-zA -Z] 'または他の文字をサポートするものに集めます。すべてのユニコード文字をサポートしている場合、配列を返すのは最良の選択ではありません... – Holger

0

以下は、これはあなたが簡単な方法は、.groupingBy(c -> c, Collectors.counting())を使用することです

import java.util.Arrays; 
import java.util.Scanner; 
import java.util.stream.Collectors; 
import java.util.stream.Stream; 

public class LetterCounter4 { 


    public static void main(String[] a) { 

    System.out.print("Input text > "); 


    countLetters(); 

} 

private static void countLetters() { 
    try{ 
     Arrays.stream(new Scanner(System.in).nextLine().toLowerCase() 
       .split("")) 
    .flatMap(line -> Stream.of(line.split("\\s+"))) 
    .map(String::toLowerCase) 
    .collect(Collectors.toMap(word -> word, word -> 1, Integer::sum)) 
    .entrySet() 
    .stream() 
    .sorted((a, b) -> a.getValue() == b.getValue() ? a.getKey().compareTo(b.getKey()) : b.getValue() - a.getValue()) 
    .forEach(System.out::println); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 

} 
} 
+1

ご返信ありがとうございます。これは確かに私が探しているものを行うだろう。しかし、私はループやif文を使いたくない。関数型プログラミングのみ。 – xtra

+0

私は自分の答えを編集しました – PrashantH

+0

"スペース"( "")を数えたい場合は、分割機能から "\\ s +"を削除することを意味します – PrashantH

関連する問題