- 문자열에서 문자 개수를 세려면 각 문자(#, $, % 같은 특수 문자 포함)를 하나씩 보며 나머지 문자들과 비교해야 함
- 비교하다 똑같은 문자를 찾으면 숫자 카운터를 1씩 증가시키면서 현재 개수 기록
public Map<Character, Integer> countDuplicateCharaters(String str) {
Map<Character, Integer> result = new HashMap<>();
// for(char ch: str.toCharArray()) {...} 사용해도 됨
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
result.compute(ch, (k, v) -> (v == null) ? 1 : ++v);
}
return result;
}
- 문자열 내 문자를 순회하며 Map을 사용해 문자를 키로, 빈도수를 값으로 저장하는 법
- 현재 문자가 Map에 없으면 (character, 1) 추가
- 현재 문자가 있으면 (character, occurrence + 1)처럼 빈도수를 1 증가
public Map<Character, Long> countDuplicatieCharacters(String str) {
Map<Character, Long> result = str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(c -> c, Collectors.counting()));
return result;
}
- 원래 문자열에 String.chars() 메서드를 호출. 이 메서드는 IntStream을 반환. IntStream은 주어진 문자열 내 문자를 정수로 표현
- mapToObj() 메서드로 IntStream을 문자 스트림으로 변환한다 (이 메서드는 정수 표현을 사람이 읽기 쉬운 문자형태로 변환)
- 문자를 분류하고(Collectors.groupingBy()) 센다(Collectors.counting())
Map<Character, Integer> result = new HashMap<>();
- 왜 'Map m = new Map' 은 안될까?
- Map -> 인터페이스이기 때문에 객체 생성 불가
- HashMap, Hashtable, Treemap -> 클래스이기 때문에 가능
- 왜 'Map m = new HashMap / Hashtable / Treemap' 으로 할까?
- (아마) 다형성 때문?
- Map 안에 'HashMap / Hashtable / Treemap' 이 있어 변경이 가능하지만,
- 'HashMap h = new HashMap 하면 HashMap' 밖에 올 수가 없어서
- .compute()
- 람다식을 통해서 기존의 값이 어떻게 연산을 할지 지정 가능
- 메서드에 넘겨주는 전달 인자의 첫 번째는 키값, 두 번째 인자는 람다식에 전달
- 주의할 점?
- 해당 키 값이 존재하지 않으면 NPE 발생하므로, 키 값이 null일 때 리턴해줄 값도 지정해야 함
Map<String, Integer> map = new HashMap<>();
map.compute("coding", (key, oldValue) -> oldValue == null ? 0 : oldValue + 1);
System.out.println(map.get("coding"));
// 실행결과 0
// key의 값이 있는게 확실 한 경우에는 아래처럼도 가능
map.compute("coding", (key, oldValue) -> oldValue + 1);
System.out.println(map.get("coding"));
// 실행결과 1
- 'stream'은 나중에 더 학습한 후에 추가하기