I'm working on a problem that requires me to store a very large amount of integers into an integer array. The input is formatted so that one line displays the amount of integers and the next displays all of the values meant to be stored. Ex:
3
12 45 67
In the problem there is closer to 100,000 integers to be stored. Currently I am using this method of storing the integers:
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
This works fine, however the problem I am solving has a strict time limit and my current solution is exceeding it. I know that there is a more efficient way to store this input using buffered readers and input streams, but I don't know how to do it, can someone please show me.
The way you are using Scanner makes your program save a String containing the whole numbers at once, in memory. With 100000 numbers in the 2nd line of your input, it is not so efficient, you could read numbers one after the other without keeping the previous one in memory. So, this way, avoiding using Scanner.readLine() should make your program run faster. You will not have to read the whole line one time, and read a 2nd time this String to parse the integers from it: you will do both of these operations only once.
Here is an example. The method testing() does not use any Scanner. The method testing2() is the one you provided. The file tst.txt contains 100000 numbers. The output from this program, on my Mac Mini (Intel Core i5#2.6GHz) is:
duration without reading one line at a time, without using a Scanner instance: 140 ms
duration when reading one line at a time with a Scanner instance: 198 ms
As you can see, not using Scanner makes your program 41% faster (integer part of (198-140)/140*100 equals 41).
package test1;
import java.io.*;
import java.util.*;
public class Test {
// Read and parse an Int from the stream: 2 operations at once
private static int readInt(InputStreamReader ir) throws IOException {
StringBuffer str = new StringBuffer();
int c;
do { c = ir.read(); } while (c < '0' || c > '9');
do {
str.append(Character.toString((char) c));
c = ir.read();
} while (!(c < '0' || c > '9'));
return Integer.parseInt(str.toString());
}
// Parsing the input step by step
private static void testing(File f) throws IOException {
InputStreamReader ir = new InputStreamReader(new BufferedInputStream(new FileInputStream(f)));
int n = readInt(ir);
int [] iVau = new int[n];
for (int i = 0; i < n; i++) iVau[i] = readInt(ir);
ir.close();
}
// Your code
private static void testing2(File f) throws IOException {
Scanner scanner = new Scanner(f);
int n = scanner.nextInt();
int[] iVau = new int[n];
scanner.nextLine();
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++)
iVau[i] = Integer.parseInt(temp[i]);
scanner.close();
}
// Compare durations
public static void main(String[] args) throws IOException {
File f = new File("/tmp/tst.txt");
// My proposal
long t = System.currentTimeMillis();
testing(f);
System.out.println("duration without reading one line at a time, without using a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
// Your code
t = System.currentTimeMillis();
testing2(f);
System.out.println("duration when reading one line at a time with a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
}
}
NOTE: creating the input file is done this way, with bash or zsh:
echo 100000 > /tmp/tst.txt
for i in {1..100000}
do
echo -n $i" " >> /tmp/tst.txt
done
I believe this is what you're looking for. A BufferedReader can only read a line at a time, so it is necessary to split the line and cast Strings to ints.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
String[] line = br.readLine().split(" ");
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(line[i]);
}
} catch (IOException e) {
e.getStackTrace();
}
Just a thought, String.split returns an array of Strings. You say the input can be around 100,000 values. So in order to split the array in this way, String.split must be iterating through each element. Now in parsing the new array of strings to Integers you have iterated through the collection twice. You could do this in one iteration with a few small tweaks.
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine();
scanner = new Scanner(tmp);
for(int i = 0; scanner.hasNextInt(); i++) {
arr[i] = scanner.nextInt();
}
The reason for linking the scanner to a String instead of leaving it on System.in is so that it ends properly. It doesn't open System.in for user input on the last token. I believe in big O notation this is the difference between O(n) and O(2n) where the original snippet is O(2n)
I am not quite sure why OP has to use Integer.parseInt(s) here since Scanner can just do the parsing directly by new Scanner(File source).
Here is a demo/test for this idea:
public class NextInt {
public static void main(String... args) {
prepareInputFile(1000, 500); // create 1_000 arrays which each contains 500 numbers;
Timer.timer(() -> readFromFile(), 20, "NextInt"); // read from the file 20 times using Scanner.nextInt();
Timer.timer(() -> readTest(), 20, "Split"); // read from the file 20 times using split() and Integer.parseInt();
}
private static void readTest() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
int n = Integer.valueOf(scanner.nextLine());
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for (int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void readFromFile() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
while (scanner.hasNextInt()) {
int arrSize = scanner.nextInt();
int[] arr = new int[arrSize];
for (int i = 0; i < arrSize; ++i) {
arr[i] = scanner.nextInt();
}
// System.out.println(Arrays.toString(arr));
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void prepareInputFile(int arrCount, int arrSize) {
Path outputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
List<String> lines = new ArrayList<>();
for (int i = 0; i < arrCount; ++i) {
int[] arr = new int[arrSize];
for (int j = 0; j < arrSize; ++j) {
arr[j] = new Random().nextInt();
}
lines.add(String.valueOf(arrSize));
lines.add(Arrays.stream(arr).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
try {
Files.write(outputPath, lines);
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
Locally tested it with 1_000 arrays while each array has 500 numbers, reading all the elements cost about: 340ms using Scanner.nextInt() while OP's method about 1.5ms.
NextInt: LongSummaryStatistics{count=20, sum=6793762162, min=315793916, average=339688108.100000, max=618922475}
Split: LongSummaryStatistics{count=20, sum=26073528, min=740860, average=1303676.400000, max=5724370}
So I really have doubt the issue lies in the input reading.
Since in your case you are aware of the total count of elements all that you have to do is to read X integers from the second line. Here is an example:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int count = in.nextInt();
int array[] = new int[count];
for (int i = 0; i < count; i++) {
array[i] = in.nextInt();
}
}
If this is not fast enough, which I doubt, then you could switch to the use of a BufferedReader as follows:
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int count = Integer.parseInt(in.readLine());
int array[] = new int[count];
for (int i = 0; i < count; i++) {
int nextInteger = 0;
int nextChar = in.read();
do {
nextInteger = nextInteger * 10 + (nextChar - '0');
nextChar = in.read();
} while (nextChar != -1 && nextChar != (int)' ');
array[i] = nextInteger;
}
}
In your case the input will be aways valid so this means that each of the integers will be separated by a single whitespace and the input will end up with EoF character.
If both are still slow enough for you then you could keep looking for more articles about Reading Integers in Java, Competative programming like this one: https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/
Still my favorite language when it comes to competitions will always be C :) Good luck and enjoy!
Related
I am doing a programming assignment that takes all of its input from stdin. The first input is an int n to tell you how many strings will follow, and the next n inputs are strings of varying lengths. The goal is to find the longest string(s) and print them.
I thought this was easy, but for the life of me, I cannot get the stdin to work with me. The eclipse arguments entered are (separated by enter):
3
a2
b3c
7
Yet I run the program, and it tells me it cannot convert from String[] to String. I do not understand how any of the above are String[]. The code is below:
import java.util.Scanner;
public class A2P1 {
public static void main(String[] args) {
int size = Integer.parseInt(args[0]);
String[] str = new String[size];
Scanner sc = new Scanner(System.in);
for (int i=0; i < size; i++) {
str[i] = sc.nextLine().split(" "); // The error
//str[i] = sc.next(); This line and the line below throw
//str[i] = sc.nextLine(); no errors, but also gives no output.
}
String[] longest = new String[size];
String[] temp = new String[size];
longest[0] = str[0];
int numToBeat = str[0].length();
int k = 0;
for (int i=0; i < size; i++) {
if (str[i].length() > numToBeat) {
numToBeat = str[i].length();
k = 0;
longest = temp;
longest[k] = str[i];
k++;
}
else if (str[i].length() == numToBeat) {
longest[k] = str[i];
}
}
System.out.println("The longest input strings are:");
for (int i=0; i < k; i++) {
System.out.println(longest[i]);
}
sc.close();
}
}
Tried:
Changing str[i] = sc.nextLine().split(" "); to its other variations in the code
Changing input values
Googling stdin for the last hour trying to find any documentation that helps me
If you are using eclipse arguments separated by enter then your logic is wrong:
according to your logic get 1st element from the eclipse argument like args[0]
another Input is taken from the console.
if you need to take all elements from the eclipse argument follow the below code:
public class A2P1 {
public static void main(String[] args) {
int size = Integer.parseInt(args[0]);
String[] str = new String[size];
int length=0;
String loggestString="";
for (int i=1; i < size; i++) {
str[i] = args[i];
int strLen = str[i].length();
if(strLen>length) {
length=strLen;
loggestString=str[i];
}
}
System.out.println(loggestString);
}
}
I am reading multiple lines from the command line looking like this:
10 12
71293781758123 72784
1 12345677654321
Then I calculate stuff with the data of each line and output exactly the same amount of lines.
Unfortunately, I never get more than one line output in the end, namely the result of the last one.
The input function looks like that:
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
String line = input.nextLine();
String[] lines = line.split(" ");
System.out.println(fct(lines[0], lines[1]));
}
input.close();
}
fct outputs a String.
Is there something weird happening I am not aware of?
Edit: I have added fct,since this could also be the problem:
public static String fct(String stringA, String stringB) {
int [] a = new int[stringA.length()];
int [] b = new int[stringB.length()];
for(int i=0; i< stringA.length(); i++) {
a[i] = stringA.charAt(i) - '0';
}
for(int i=0; i< stringB.length(); i++) {
b[i] = stringB.charAt(i) - '0';
}
if(a.length < b.length) {
int[] c = a.clone();
a = b.clone();
b = c.clone();
}
Stack<Integer> s = new Stack<Integer>();
int carry = 0;
int b_ind = b.length -1;
for(int i=a.length-1; i>=0; i--) {
if(b_ind >= 0) {
int diff = a[i] - b[b_ind] - carry;
if(diff < 0) {
carry = 1;
diff = 10 + diff;
} else {
carry = 0;
}
s.push(diff);
} else {
if(carry==0) {
s.push(a[i]);
} else {
s.push(a[i]-carry);
carry = 0;
}
}
b_ind -= 1;
}
String all = "";
while(!s.empty()) {
all = all + s.pop();
}
return all.replaceFirst("^0+(?!$)", "").trim();
}
The output would then be:
2
71293781685339
12345677654320
Being directly on the console on the line after the input finished.
Add one line break after last input line 1 12345677654321. Otherwise program won't read last line till you press enter(return) key.
If you want output on console like this:
10 12
71293781758123 72784
1 12345677654321
98
71293781685339
12345677654320
But you are getting this:
10 12
71293781758123 72784
1 1234567765432198
71293781685339
Notice, 98 is getting appended to last input line. And the second output is on the next line. You actually have two outputs.
And the third input has not been read by the program because third input line doesn't end in new line. If you press Enter key here the program will process the third input.
You need to make sure that there is a new line character after last input line before pasting entire input in to console.
Just a sidenote:
I would use java.math.BigInteger in this context (math with big integers).
import java.util.Scanner;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
try (var scanner = new Scanner(System.in)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] lines = line.split(" ");
System.out.println(fct(lines[0], lines[1]));
}
}
}
public static String fct(String numberA, String numberB) {
var a = new BigInteger(numberA);
var b = new BigInteger(numberB);
return a.subtract(b).abs().toString();
}
}
I'm trying to read a large text file of about 7516 lines of text. When I read a smaller file (9 lines) the program works fine. But with the large file it seems to get caught in something and just keeps running without anything actually happening.I'm not sure where to start looking for the issue.
The code reads a text file and then turn it into an array. Then it passes the array into a shuffle and writes it into another text file. Or at least that's what I want it to do.
package Rn1;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Read2 {
static void randomShuffle( int arr[], int n)
{
// Creating a object for Random class
Random r = new Random();
// Start from the last element and swap one by one. We don't
// need to run for the first element that's why i > 0
for (int i = n-1; i > 0; i--) {
// Pick a random index from 0 to i
int j = r.nextInt(i+1);
// Swap arr[i] with the element at random index
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// Prints the random array
System.out.println(Arrays.toString(arr));
}
public static String readString(String file) {
String text = "";
try {
Scanner s = new Scanner(new File(file));
while(s.hasNext()) {
text = text + s.next() + " ";
}
}
catch(FileNotFoundException e) {
System.out.println("Not Found");
}
return text;
}
public static String[] readArray(String file) {
//Step 1:
//Count how many elements in the file (lines)
//Step 2
//Create array
int ctr = 0;
try {
Scanner s1 = new Scanner(new File(file));
while (s1.hasNextLine()) {
ctr = ctr +1;
if (s1.hasNext()) {
s1.next();
}
}
String[] words = new String[ctr];
Scanner s2 = new Scanner(new File(file));
for(int i = 0; i < ctr; i = i+1){
words[i] = s2.next();
}
return words;
}
catch (FileNotFoundException e) {
}
return null;
}
public static void main(String[] args) throws Exception
{
//String text = readString("C:\\Users\\herna\\Desktop\\Test.txt");
//System.out.println(text);
String[] words = readArray("C:\\Users\\herna\\Desktop\\ErdosCA.txt");
int n = words.length;
int [] arr = new int [n];
PrintWriter writer = new PrintWriter("the-file-name.txt", "UTF-8");
for (int i=0; i < words.length; i = i + 1 )
{
arr[i] = Integer.parseInt(words[i]);
//writer.println(words[i]);
}
//System.out.println(Arrays.toString(arr));
randomShuffle(arr, n);
writer.println(Arrays.toString(arr));
//writer.println(Arrays.toString(words));
//writer.println("Update*");
writer.close();
}
}
The program is also reproducable with small files, for example:
1
2
3
The program enters an endless loop when the last line of the file is empty. The bad part is this:
Scanner s1 = new Scanner(new File(file));
while (s1.hasNextLine())
{
ctr = ctr + 1;
if (s1.hasNext())
{
s1.next();
}
}
If you are before the empty line, then s1.hasNextLine() is true but s1.hasNext() is false. So you do not read the next element. Then in the next iteration of the loop, s1.hasNextLine() is still true, and thus the loop does never end.
By the way, you should never catch Exceptions without handling them. You should at least output an error message and then call e.printStackTrace().
Even if I think that I solved a competitive programming problem from HackerEarth with the best approach, all tests exceed the time limit. I really do not know how to optimize it further because it is just an easy exercise.
My approach: iterate over all array members than add them to a HashMap which stores their occurrences. After that simply read the query numbers and get their occurence from the HashMap.
This is my solution:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
class TestClass {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
//go through all test cases
for (int i = 0; i < t; i++) {
Map<Integer, Integer> map = new HashMap<>();
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
//read array
for (int j = 0; j < N; j++) {
int x = Integer.parseInt(inputs[j]);
Integer value = map.get(x);
//if number is already in hashmap then increment its count
//else put it into the map with a count of 1
if (value == null) {
map.put(x, 1);
} else map.put(x, value + 1);
}
//iterate through the queries and get their occurences from the map
for (int j = 0; j < Q; j++) {
int x = Integer.parseInt(br.readLine());
Integer value = map.get(x);
if (value == null) {
System.out.println(0);
} else System.out.println(value);
}
}
}
}
My question is: what can be the problem with my approach? Why does it run out of time?
Ok, so the problem is not so obvious. I took a look at the input files and they are huge so you have to use some really fast method for writing to the console(many test cases -->> many answers). You can use PrinteWriter for that.
Working solution:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
class TestClass {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pr = new PrintWriter(System.out);
int t = Integer.parseInt(br.readLine());
//go through all test cases
for (int i = 0; i < t; i++) {
Map<Integer, Integer> map = new HashMap<>();
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
//read array
for (int j = 0; j < N; j++) {
int x = Integer.parseInt(inputs[j]);
Integer value = map.get(x);
//if number is already in hashmap then increment its count
//else put it into the map with a count of 1
if (value == null) {
map.put(x, 1);
} else map.put(x, value + 1);
}
//iterate through the queries and get their occurences from the map
for (int j = 0; j < Q; j++) {
int x = Integer.parseInt(br.readLine());
Integer value = map.get(x);
if (value == null) {
pr.println(0);
} else pr.println(value);
}
}
pr.close();
}
}
Yes, I know that it is strange that the exercise itself is not so hard, but reading the input and writing the result is the big part of it.
The problem with your approach is primarily it's use of BufferedReader, and the consequential information parsing you're preforming. Try an approach with scanner.
import java.util.*;
class TestClass {
public static void main(String args[] ) throws Exception {
Scanner s = new Scanner(System.in);
int T = s.nextInt();
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<T;i++)
{
StringBuilder sb=new StringBuilder();
int N=s.nextInt();
int Q=s.nextInt();
int[] arr=new int[N];
for(int j=0;j<N;j++)
{
arr[j]=s.nextInt();
if(map.containsKey(arr[j]))
{
map.put(arr[j],map.get(arr[j])+1);
}
else
map.put(arr[j],1);
}
for(int k=0;k<Q;k++)
{
int X=s.nextInt();
if(map.containsKey(X)){
sb.append(map.get(X)+"\n");
}
else{
sb.append(0+"\n");
}
}
System.out.println(sb.toString());
map.clear();
}
}
}
This will remove a lot of the unnecessary parsing you are doing with:
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
Please look at Scanner vs. BufferedReader to understand why Scanner is situationally faster here. Essentially BufferedReader is faster in it's ability to simply read the lines, but when you use BufferedReader here, you are then forced to use Integer.parseInt(...) and br.readlines().split(" ") to parse the information you need from the input; however, scanner has built in parsing mechanisms that can read and parse the data asynchronously. As you will see, this approach passes the test in 4-8 seconds. Additionally you could benefit from using StringBuilder, and not using:
Integer value = map.get(x);
if (value == null) {
pr.println(0);
} else pr.println(value);
With the built in method map.containsKey(x).
Scanner is used for parsing tokens from the contents of the stream while BufferedReader just reads the stream and does not do any special
parsing.
In fact you can pass a BufferedReader to a scanner as the source of
characters to parse.
Furthermore:
A scanner on the other hand has a lot more cheese built into it; it
can do all that a BufferedReader can do and at around the same level of
efficiency as well. However, in addition a Scanner can parse the
underlying stream for primitive types and strings using regular
expressions. It can also tokenize the underlying stream with the
delimiter of your choice. It can also do forward scanning of the
underlying stream disregarding the delimiter!
There is a large difference in runtime when you have to call
inputs = br.readLine().split(" "); and Integer.parseInt(..) multiple times, versus simply calling s.nextInt(). You are already reading the data with br.readLine(), when you call Integer.parseInt(...) the data is read again by the parseInt() function.
I'm supposed to sort a char array and print it in descending order. Should be simple, however, I'm not getting the output I want. All solutions around the internet tells me Arrays.sort is okay to use, but am I supposed to use another method? Or am I overlooking something?
public class mainClassTextFile {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("file.txt");
String fileContents = "";
int i;
int loopcount = 0;
int count = 0;
while((i = fileReader.read())!=-1){
char ch = (char)i;
fileContents = fileContents + ch;
}
char[] ch=fileContents.toCharArray();
for(int n = 0; n < ch.length; n++) {
boolean addCharacter=true;
for(int t = 0; t < n; t++) {
if (ch[n] == (fileContents.charAt(t)))
addCharacter=false;
}
if (addCharacter) {
for(int j = 0; j < fileContents.length(); j++) {
if(ch[n]==fileContents.charAt(j))
count=count+1;
}
Arrays.sort(ch);
System.out.print(ch[n] + ": "+(count));
System.out.println();
count=0;
loopcount++;
}
}
}
}
The output is supposed to be all the characters in the text, counted and sorted, however this is the result:
: 3339
X: 4
X: 4
X: 4
X: 4
[: 2
]: 2
If I // Arrays.sort() then I get all the characters in the text file counted correctly, however they are neither sorted or in descending order!
Your for-loop really doesnot make sense to me but if you want to read string from a file convert it to charArray and sort it you can do it this way
FileReader fileReader = new FileReader("yourFile.txt");
StringBuilder br = new StringBuilder();
while(true){
int ch = fileReader.read();
if(ch==-1)
break;
char chArr = (char)ch;
br.append(chArr);
}
char[] ch=br.toString().replaceAll("\\s+", "").toCharArray(); //removed all spaces
System.out.println(Arrays.toString(ch));
Arrays.sort(ch);
System.out.println("After sorting : "+Arrays.toString(ch)); // ascending order
for(int i = ch.length - 1; i >= 0; i--)
System.out.println(arr[i]); //descending order
Your code had a lot of mistakes, including conceptual ones; so instead of getting into detailed explanations on how it could be corrected, I submit code which works and which I tried to make as similar to yours:
public static void main(String[] args) throws IOException {
final String fileContents;
try (Scanner sc = new Scanner(new File("file.txt"))) {
fileContents = sc.useDelimiter("\\Z").next();
}
final char[] ch = fileContents.toCharArray();
Arrays.sort(ch);
int prevChar = -1, count = 0;
for (int i = 0; i < ch.length; i++) {
if (ch[i] != prevChar) {
if (count > 0) System.out.println((char)prevChar + ": "+count);
count = 1;
prevChar = ch[i];
} else count++;
}
if (count > 0) System.out.println((char)prevChar + ": "+count);
}
Note that I took the liberty to completely change the routine to load the whole file as a String. This is because I regard file reading as a side concern here.
The loop works by going through the sorted array and emitting count each time it encounters a character different from the previous one. In the end we have a duplicated line of code which prints the final character.