I'm trying to count and print the frequency of all characters in a text.
I want to do this using an Array
or ArrayList
and no maps with key-value pairs.
The code below gives the preferred result.
I want to get rid of the for
loop of main
And do all the work in method countLetters()
.
To be clear, I wish to do this in a functional way not using any for loops or if statements. Can this be done? And if so, how?
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();
}
}
The straightforward way is to use .groupingBy(c -> c, Collectors.counting())
. The code would be simpler and won't blow up when somebody enters À or some other letter outside [a-zA-Z] range. But that would create a Map
, which you say you don't want.
If you specifically wish to stick with arrays and lists, here's a way to do it:
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])
);
}