2017-12-26 49 views
0

텍스트의 모든 문자 빈도를 계산하여 인쇄하려고합니다. Array 또는 ArrayList을 사용하고 키 - 값 쌍이있는지도가 필요하지 않습니다.스트림, 맵, 키 - 값 쌍을 사용하지 않고 텍스트의 문자 빈도 계산 및 인쇄

아래 코드는 바람직한 결과를 제공합니다. for 루프를 제거하고 싶습니다. 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

답장을 보내 주셔서 감사합니다. 이것은 실제로 내가 원하는 것을 할 것입니다. 그러나 for 루프와 if 문을 사용하고 싶지 않습니다. 함수형 프로그래밍 만. – xtra

+0

내 대답을 편집했습니다. – PrashantH

+0

을 확인하십시오. "공백"("")을 계산하려면 "\\ s +"를 분리 함수 – PrashantH