How can i keep track of multiple counter variables - java

I have written some code that count the number of "if" statements from unknown number of files. How can i keep a count for each file separate and a total of "if" from all files?
code:
import java.io.*;
public class ifCounter4
{
public static void main(String[] args) throws IOException
{
// variable to keep track of number of if's
int ifCount = 0;
for (int c = 0; c < args.length; c++)
{
// parameter the TA will pass in
String fileName = args[c];
// create a new BufferReader
BufferedReader reader = new BufferedReader( new FileReader (fileName));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
// read from the text file
while (( line = reader.readLine()) != null)
{
stringBuilder.append(line);
stringBuilder.append(ls);
}
// create a new string with stringBuilder data
String tempString = stringBuilder.toString();
// create one last string to look for our valid if(s) in
// with ALL whitespace removed
String compareString = tempString.replaceAll("\\s","");
// check for valid if(s)
for (int i = 0; i < compareString.length(); i++)
{
if (compareString.charAt(i) == ';' || compareString.charAt(i) == '}' || compareString.charAt(i) == '{') // added opening "{" for nested ifs :)
{
i++;
if (compareString.charAt(i) == 'i')
{
i++;
if (compareString.charAt(i) == 'f')
{
i++;
if (compareString.charAt(i) == '(')
ifCount++;
} // end if
} // end if
} // end if
} // end for
// print the number of valid "if(s) with a new line after"
System.out.println(ifCount + " " + args[c]); // <-- this keeps running total
// but not count for each file
}
System.out.println();
} // end main
} // end class

You can create a Map that stores the file names as keys and the count as values.
Map<String, Integer> count = new HashMap<String, Integer>();
After each file,
count.put(filename, ifCount);
ifcount = 0;
Walk the value set to get the total.

How about a Map which uses the file name as key and keeps the count of ifs as value? For overall count, store it in its own int, or just calculate it when needed by adding up all the values in the Map.
Map<String, Integer> ifsByFileName = new HashMap<String, Integer>();
int totalIfs = 0;
for each if in "file" {
totalIfs++;
Integer currentCount = ifsByFileName.get(file);
if (currentCount == null) {
currentCount = 0;
}
ifsByFileName.put(file, currentCount + 1);
}
// total from the map:
int totalIfsFromMap = 0;
for (Integer fileCount : ifsByFileName.values()) {
totalIfsFromMap += fileCount;
}

Using an array would solve this problem.
int[] ifCount = new int[args.length];
and then in your loop ifCount[c]++;

Problematic in this scenario is when many threads want to increase the same set of counters.
Operations such as ifCount[c]++; and ifsByFileName.put(file, currentCount + 1);are not thread safe.
The obvious solution to use a ConcurrentMap and AtomicLong is also insufficient, since you must place the initial values of 0, which would require additional locking.
The Google Guava project provides a convenient out of the box sollution: AtomicLongMap
With this class you can write:
AtomicLongMap<String> cnts = AtomicLongMap.create();
cnts.incrementAndGet("foo");
cnts.incrementAndGet("bar");
cnts.incrementAndGet("foo");
for (Entry<String, Long> entry : cnts.asMap().entrySet()) {
System.out.println(entry);
}
which prints:
foo=2
bar=1
And is completely thread safe.

This is a counter that adds to 100 and if you edit the value of N it puts a * next to the multiples of.
public class SmashtonCounter_multiples {
public static void main(String[] args) {
int count;
int n = 3; //change this variable for different multiples of
for(count = 1; count <= 100; count++) {
if((count % n) == 0) {
System.out.print(count + "*");
}
else {
System.out.print(count);
if (count < 100) {
System.out.print(",");
}
}
}
}

Related

Fixing a looping issue for removing letters in a String

So i'm making a program that removes duplicate letters in a string. The last step of it is updating the old string to the new string, and looping through the new string. I believe everything works besides the looping through the new string part. Any ideas what might be causing it to not work? It will work as intended for one pass through, and then after that it won't step through the new loop
public class homework20_5 {
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
int i;
for (i = 0; i < kb.length(); i++) {
char temp = kb.charAt(i);
if(temp == kb.charAt(i+1)) {
kb = kb.replace(""+temp, "");
i = kb.length() + i;
}
}
System.out.println(kb);
}
}
Instead of using complex algorithms and loops like this you can just use HashSet which will work just like a list but it won't allow any duplicate elements.
private static String removeDuplicateWords(String str) {
HashSet<Character> xChars = new LinkedHashSet<>();
for(char c: str.toCharArray()) {
xChars.add(c);
}
StringBuilder sb = new StringBuilder();
for (char c: xChars) {
sb.append(c);
}
return sb.toString();
}
So you actually want to remove all occurrences that appear more than once entirely and not just the duplicate appearances (while preserving one instance)?
"Yea that’s exactly right "
In that case your idea won't cut it because your duplicate letter detection can only detect continuous sequences of duplicates. A very simple way would be to use 2 sets in order to identify unique letters in one pass.
public class RemoveLettersSeenMultipleTimes {
public static void main(String []args){
String input = "abcabdgag";
Set<Character> lettersSeenOnce = lettersSeenOnceIn(input);
StringBuilder output = new StringBuilder();
for (Character c : lettersSeenOnce) {
output.append(c);
}
System.out.println(output);
}
private static Set<Character> lettersSeenOnceIn(String input) {
Set<Character> seenOnce = new LinkedHashSet<>();
Set<Character> seenMany = new HashSet<>();
for (Character c : input.toCharArray()) {
if (seenOnce.contains(c)) {
seenMany.add(c);
seenOnce.remove(c);
continue;
}
if (!seenMany.contains(c)) {
seenOnce.add(c);
}
}
return seenOnce;
}
}
There are a few problems here:
Problem 1
for (i = 0; i < kb.length(); i++) {
should be
for (i = 0; i < kb.length() - 1; i++) {
Because this
if (temp == kb.charAt(i+1))
will explode with an ArrayIndexOutOfBoundsException otherwise.
Problem 2
Delete this line:
i = kb.length() + i;
I don't understand what the intention is there, but nevertheless it must be deleted.
Problem 3
Rather than lots of code, there's a one-line solution:
String deduped = kb.replaceAll("[" + input.replaceAll("(.)(?=.*\\1)|.", "$1") + "]", "");
This works by:
finding all dupe chars via input.replaceAll("(.)(?=.*\\1)|.", "$1"), which in turn works by consuming every character, either capturing it as group 1 if it has a dupe or just consuming it if a non-dupe
building a regex character class from the dupes, which is used to delete them all (replace with a blank)
Say you feed the program with the input "AAABBC", then the expected output should be "ABC".
Now in the for-loop, i gets incremented from 0 to 5.
After 1st iteration:
kb becomes AABBC and i becomes 5 + 0 = 5 and gets incremented to 6.
And now the condition for the for-loop is that i < kb.length() which equates to 6 < 5 returning false. Hence the for-loop ends after just one iteration.
So the problematic line of code is i = kb.length() + i; and also the loop condition keeps changing as the size of kb changes.
I would suggest using a while loop like the following example if you don't worry too much about the efficiency.
public static void main(String[] arg) {
String kb = "XYYYXAC";
int i = 0;
while (i < kb.length()) {
char temp = kb.charAt(i);
for (int j = i + 1; j < kb.length(); j++) {
char dup = kb.charAt(j);
if (temp == dup) {
kb = removeCharByIndex(kb, j);
j--;
}
}
i++;
}
System.out.println(kb);
}
private static String removeCharByIndex(String str, int index) {
return new StringBuilder(str).deleteCharAt(index).toString();
}
Output: XYAC
EDIT: I misunderstood your requirements. So looking at the above comments, you want all the duplicates and the target character removed. So the above code can be changed like this.
public static void main(String[] arg) {
String kb = "XYYYXAC";
int i = 0;
while (i < kb.length()) {
char temp = kb.charAt(i);
boolean hasDup = false;
for (int j = i + 1; j < kb.length(); j++) {
if (temp == kb.charAt(j)) {
hasDup = true;
kb = removeCharByIndex(kb, j);
j--;
}
}
if (hasDup) {
kb = removeCharByIndex(kb, i);
i--;
}
i++;
}
System.out.println(kb);
}
private static String removeCharByIndex(String str, int index) {
return new StringBuilder(str).deleteCharAt(index).toString();
}
Output: AC
Although, this is not the best and definitely not an efficient solution to this, I think you can get the idea of iterating the input string character by character and removing it if it has duplicates.
The following answer concerns only the transformation of XYYYXACX to ACX. If we wanted to have AC, it's a whole different answer. The other answers already speak about it, and I'll invite you to consult the contains method of String too.
We should consider avoiding -most of the time- modifying the things we iterate. Using a temporary variable could be a kind of solution. To use it, we could change our mindset. Instead of erasing the undesired letters, we can save the ones we want.
To identify the desired character, we need to test if all surrounding letters are different from the tested one. It'll be the opposite of what you did with if(temp == kb.charAt(i+1)) { like if(temp != kb.charAt(i+1)) {. But considering that the tested string will not change anymore, we will need to test the previous letter too as if(temp != kb.charAt(i-1) && temp != kb.charAt(i+1)) {.
As previously said, once we have identified the letter, we will keep the value with a temporary variable. That will lead to replace kb = kb.replace(""+temp, ""); by buffer = buffer + temp; if buffer is our temporary variable initialized with an empty string (Aka. String buffer = "";). In the end, we could override our base value with the temporary one.
At this step, we will have:
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
String buffer = "";
int i;
for (i = 1; i < kb.length(); i++) {
char temp = kb.charAt(i);
if(temp != kb.charAt(i-1) && temp != kb.charAt(i+1)) {
buffer = buffer + temp;
}
}
kb = buffer;
System.out.println(kb);
}
That'll sadly not work, trying to access invalid indexes of our string. We should consider two particular behavior for the first and the last letter because they are close to only one letter. For these letters, we will have only one comparison. So, we can make them inside or outside the loop. For clarity, we will do it outside.
For the first one, it will look like to if (kb.charAt(0) != kb.charAt(1)) { and at if (kb.charAt(kb.length() - 1) != kb.charAt(kb.length() - 2)) { for the last. The body of the condition will remain the same as the one in the loop.
Once done, we will reduce the scope of our loop to exclude these character with for (i = 1; i < (kb.length() - 1); i++) {.
Now we will have something working, but only for one iteration:
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
String buffer = "";
int i;
if (kb.charAt(0) != kb.charAt(1)) {
buffer = buffer + kb.charAt(0);
}
for (i = 1; i < (kb.length() - 1); i++) {
char temp = kb.charAt(i);
if(temp != kb.charAt(i-1) && temp != kb.charAt(i+1)) {
buffer = buffer + temp;
}
}
if (kb.charAt(kb.length() - 1) != kb.charAt(kb.length() - 2)) {
buffer = buffer + kb.charAt(kb.length() - 1);
}
kb = buffer;
System.out.println(kb);
}
XYYYXACX will become XXACX.
Once said, our index problem can occur again if the string has only one letter. However, all of this would have been useless because obviously, we can't have a duplicate letter in this situation. As a fact, we should wrap the whole thing to ensure that we have at least two letters:
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
if (kb.length() >= 2) {
String buffer = "";
int i;
if (kb.charAt(0) != kb.charAt(1)) {
buffer = buffer + kb.charAt(0);
}
for (i = 1; i < (kb.length() - 1); i++) {
char temp = kb.charAt(i);
if (temp != kb.charAt(i - 1) && temp != kb.charAt(i + 1)) {
buffer = buffer + temp;
}
}
if (kb.charAt(kb.length() - 1) != kb.charAt(kb.length() - 2)) {
buffer = buffer + kb.charAt(kb.length() - 1);
}
kb = buffer;
}
System.out.println(kb);
}
The last thing to do is perform this treatment until we have no more undesired letters. For this task, the do { ... } while ( ... ) seems perfect. We can use for the condition comparison the size of the string. Because when the size of the previous iteration is equal to the temporary variable, we will know that we have finished.
We will need to perform this comparison before affecting the value of our temporary variable to the base one. Otherwise, it'll always be the same.
In the end, the following thing should be a potential solution:
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
Boolean modified;
do {
modified = false;
if (kb.length() >= 2) {
String buffer = "";
int i;
if (kb.charAt(0) != kb.charAt(1)) {
buffer = buffer + kb.charAt(0);
}
for (i = 1; i < (kb.length() - 1); i++) {
char temp = kb.charAt(i);
if (temp != kb.charAt(i - 1) && temp != kb.charAt(i + 1)) {
buffer = buffer + temp;
}
}
if (kb.charAt(kb.length() - 1) != kb.charAt(kb.length() - 2)) {
buffer = buffer + kb.charAt(kb.length() - 1);
}
modified = (kb.length() != buffer.length());
kb = buffer;
}
} while (modified);
System.out.println(kb);
}
Take note that this code is ugly for the sole purpose of the explanation. We should refactor this code. We can improve it a lot for the sake of brevity and, why not, performance.

Splitting this string to get the max count to a corresponding character

I am currently implementing Run Length Encoding for text compression and my algorithm does return Strings of the following form:
Let's say we have a string as input
"AAAAABBBBCCCCCCCC"
then my algorithm returns
"1A2A3A4A5A1B2B3B4B1C2C3C4C5C6C7C8C"
Now I want to apply Java String split to solve this, because I want to get the highest number corresponding to character. For our example it would be
"5A4B8C"
My function can be seen below
public String getStrfinal(){
String result = "";
int counter = 1;
StringBuilder sb = new StringBuilder();
sb.append("");
for (int i=0;i<str.length()-1;i++) {
char c = str.charAt(i);
if (str.charAt(i)==str.charAt(i+1)) {
counter++;
sb.append(counter);
sb.append(c);
}
else {
counter = 1;
continue;
}
}
result = sb.toString();
return result;
}
public static String getStrfinal(){
StringBuilder sb = new StringBuilder();
char last = 0;
int count = 0;
for(int i = 0; i < str.length(); i++) {
if(i > 0 && last != str.charAt(i)) {
sb.append(count + "" + last);
last = 0;
count = 1;
}
else {
count++;
}
last = str.charAt(i);
}
sb.append(count + "" + last);
return sb.toString();
}
Here is one possible solution. It starts with the raw string and simply iterates thru the string.
public static void main(String[] args) {
String input = "AAAABBBCCCCCCCDDDEAAFBBCD";
int index = 0;
StringBuilder sb = new StringBuilder();
while (index < input.length()) {
int count = 0;
char c = input.charAt(index);
for (; index < input.length(); index++) {
if (c != input.charAt(index)) {
count++;
}
else {
break;
}
}
sb.append(Integer.toString(count));
sb.append(c);
count = 0;
}
System.out.println(sb.toString());
}
But one problem with this method and others is what happens if there are digits in the text? For example. What if the string is AAABB999222AAA which would compress to 3A2B39323A. That could also mean AAABB followed by 39 3's and 23 A's
Instead of string Buffer you can use a map it will be much easier and clean to do so.
public static void main(String[] args) {
String input = "AAAAABBBBCCCCCCCCAAABBBDDCCCC";
int counter=1;
for(int i=1; i<input.length(); i++) {
if(input.charAt(i-1)==input.charAt(i)) {
counter=counter+1;
}else if(input.charAt(i-1)!=input.charAt(i)){
System.out.print(counter+Character.toString(input.charAt(i-1)));
counter=1;
}if(i==input.length()-1){
System.out.print(counter+Character.toString(input.charAt(i)));
}
}
}
This will gives
5A4B8C3A3B2D4C
UPDATES
I Agree with #WJS if the string contains number the out put becomes messy
hence if the System.out in above code will be exchange with below i.e.
System.out.print(Character.toString(input.charAt(i-1))+"="+counter+" ");
then for input like
AAAAABBBBCCCCCCCCAAABBBDD556677CCCCz
we get out put as below
A=5 B=4 C=8 A=3 B=3 D=2 5=2 6=2 7=2 C=4 z=1
This is one of the possible solutions to your question. We can use a LinkedHashMap data structure which is similar to HashMap but it also maintains the order. So, we can traverse the string and store the occurrence of each character as Key-value pair into the map and retrieve easily with its maximum occurrence.
public String getStrFinal(String str){
if(str==null || str.length()==0) return str;
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
StringBuilder sb=new StringBuilder(); // to store the final string
for(char ch:str.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1); // put the count for each character
}
for(Map.Entry<Character,Integer> entry:map.entrySet()){ // iterate the map again and append each character's occurence into stringbuilder
sb.append(entry.getValue());
sb.append(entry.getKey());
}
System.out.println("String = " + sb.toString()); // here you go, we got the final string
return sb.toString();
}

Java Write to File Perfomance

i am trying to write to file with redirection from command line.
my programm is very slow when i read a file of 25MB and 90% of execution time spent in "System.out.println" .I tried some other methods than System.out.print but coulnt fix..
which method i have to use to print a big ArrayList? (with redirection)
i would appreciate your help and an example
thanks
here is my code:
public class Ask0 {
public static void main(String args[]) throws IOException {
int i = 0, token0, token1;
String[] tokens;
List<String> inputList = new ArrayList<>();
Map<Integer, List<Integer>> map = new HashMap<>();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
while ((input = br.readLine()) != null) {
tokens = input.split("\\|");
inputList.add(tokens[0] + "|" + tokens[1]);
token0 = Integer.parseInt(tokens[0]);
token1 = Integer.parseInt(tokens[1]);
List<Integer> l = map.get(token0);
if (l == null) {
l = new ArrayList<>();
map.put(token0, l);
}
if (l.contains(token1) == false) {
l.add(token1);
}
i++;
}
i = 0;
for (int j = inputList.size(); j > 0; j--) {
tokens = inputList.get(i).split("\\|");
token0 = Integer.parseInt(tokens[0]);
token1 = Integer.parseInt(tokens[1]);
List l = map.get(token0);
System.out.println(tokens[0] + "|" + tokens[1] + "["
+ (l.indexOf(token1) + 1) + "," + l.size() + "]");
i++;
}
}
}
Input
3|78 4|7765 3|82 2|8 4|14 3|78 2|8 4|12
Desired result
3|78[1,2] 4|7765[1,3] 3|82[2,2] 2|8[1,1] 4|14[2,3] 3|78[1,2] 2|8[1,1] 4|12[3,3]
For speed, the below code:
Uses a StringBuilder for fast concatenation into a resulting String and fast output since only one massive String is printed at the end, saving unnecessary buffer flushes.
Doesn't create a bunch of Strings when parsing the input, just a small byte[] and Integers in an ArrayList.
Manually uses a 64kiB buffer for reading.
Doesn't rejoin the tokens with "|" in the middle only to split them again later.
Uses a HashMap<Integer, HashMap<Integer, Integer>> instead of a HashMap<Integer, ArrayList<Integer>> to save time on element lookups in the list (turns algorithm from O(n2) time to O(n) time).
Some speedups that might not work as you want:
Doesn't waste time properly handling Unicode.
Doesn't waste time properly handling negative or overflowed numbers.
Doesn't care what the separator characters are (you could input "1,2,3,4,5,6" instead and it would still work just like "1|2\n3|4\n5|6\n").
You can see that it gives the correct results for your test input here (except that it separates the outputs by newlines like in your code).
private static final int BUFFER_SIZE = 65536;
private static enum InputState { START, MIDDLE }
public static void main(final String[] args) throws IOException {
// Input the numbers
final byte[] inputBuffer = new byte[BUFFER_SIZE];
final List<Integer> inputs = new ArrayList<>();
int inputValue = 0;
InputState inputState = InputState.START;
while (true) {
int j = 0;
final int bytesRead = System.in.read(inputBuffer, 0, BUFFER_SIZE);
if (bytesRead == -1) {
if (inputState == InputState.MIDDLE) {
inputs.add(inputValue);
}
break;
}
for (int i = 0; i < bytesRead; i++) {
byte ch = inputBuffer[i];
int leftToken = 0;
if (ch < 48 || ch > 57) {
if (inputState == InputState.MIDDLE) {
inputs.add(inputValue);
inputState = InputState.START;
}
}
else {
if (inputState == InputState.START) {
inputValue = ch - 48;
inputState = InputState.MIDDLE;
}
else {
inputValue = 10*inputValue + ch - 48;
}
}
}
}
System.in.close();
// Put the numbers into a map
final Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
for (int i = 0; i < inputs.size();) {
final Integer left = inputs.get(i++);
final Integer right = inputs.get(i++);
final Map<Integer, Integer> rights;
if (map.containsKey(left)) {
rights = map.get(left);
}
else {
rights = new HashMap<>();
map.put(left, rights);
}
rights.putIfAbsent(right, rights.size() + 1);
}
// Prepare StringBuilder with results
final StringBuilder results = new StringBuilder();
for (int i = 0; i < inputs.size();) {
final Integer left = inputs.get(i++);
final Integer right = inputs.get(i++);
final Map<Integer, Integer> rights = map.get(left);
results.append(left).append('|').append(right);
results.append('[').append(rights.get(right)).append(',');
results.append(rights.size()).append(']').append('\n');
}
System.out.print(results);
}
You can alternatively manually use a 64 kiB byte[] output buffer with System.out.write(outputBuffer, 0, bytesToWrite); System.out.flush(); as well if you want to save memory, though that's a lot more work.
Also, if you know the minimum and maximum values that you'll see, you can use int[] or int[][] arrays instead of Map<Integer, Integer> or Map<Integer, Map<Integer, Integer>>, though that's somewhat more involved as well. It would be very fast, though.

I want the string pattern aabbcc to be displayed as 2a2b2c

I have somehow got the output with the help of some browsing. But I couldn't understand the logic behind the code. Is there any simple way to achieve this?
public class LetterCount {
public static void main(String[] args)
{
String str = "aabbcccddd";
int[] counts = new int[(int) Character.MAX_VALUE];
// If you are certain you will only have ASCII characters, I would use `new int[256]` instead
for (int i = 0; i < str.length(); i++) {
char charAt = str.charAt(i);
counts[(int) charAt]++;
}
for (int i = 0; i < counts.length; i++) {
if (counts[i] > 0)
//System.out.println("Number of " + (char) i + ": " + counts[i]);
System.out.print(""+ counts[i] + (char) i + "");
}
}
}
There are 3 conditions which need to be taken care of:
if (s.charAt(x) != s.charAt(x + 1) && count == 1) ⇒ print the counter and character;
if (s.charAt(x) == s.charAt(x + 1)) ⇒ increase the counter;
if (s.charAt(x) != s.charAt(x + 1) && count >= 2) ⇒ reset to counter 1.
{
int count= 1;
int x;
for (x = 0; x < s.length() - 1; x++) {
if (s.charAt(x) != s.charAt(x + 1) && count == 1) {
System.out.print(s.charAt(x));
System.out.print(count);
}
else if (s.charAt(x)== s.charAt(x + 1)) {
count++;
}
else if (s.charAt(x) != s.charAt(x + 1) && count >= 2) {
System.out.print(s.charAt(x));
System.out.print(count);
count = 1;
}
}
System.out.print(s.charAt(x));
System.out.println(count);
}
The code is really simple.It uses the ASCII value of a character to index into the array that stores the frequency of each character.
The output is simply got by iterating over that array and which character has frequency greater than 1, print it accordingly as you want in the output that is frequency followed by character.
If the input string has same characters consecutive then the solution can be using space of O(1)
For example in your string aabbcc, the same characters are consecutive , so we can take advantage of this fact and count the character frequency and print it at the same time.
for (int i = 0; i < str.length(); i++)
{
int freq = 1;
while((i+1)<str.length()&&str.charAt(i) == str.charAt(i+1))
{++freq;++i}
System.out.print(freq+str.charAt(i));
}
You are trying to keep count of the number of times each character is found. An array is referenced by an index. For example, the ASCII code for the lowercase letter a is the integer 97. Thus the count of the number of times the letter a is seen is in counts[97]. After every element in the counts array has been set, you print out how many have been found.
This should help you understand the basic idea behind how to approach the string compression problem
import java.util.*;
public class LetterCount {
public static void main(String[] args) {
//your input string
String str = "aabbcccddd";
//split your input into characters
String chars[] = str.split("");
//maintain a map to store unique character and its frequency
Map<String, Integer> compressMap = new LinkedHashMap<String, Integer>();
//read every letter in input string
for(String s: chars) {
//java.lang.String.split(String) method includes empty string in your
//split array, so you need to ignore that
if("".equals(s))
continue;
//obtain the previous occurances of the character
Integer count = compressMap.get(s);
//if the character was previously encountered, increment its count
if(count != null)
compressMap.put(s, ++count);
else//otherwise store it as first occurance
compressMap.put(s, 1);
}
//Create a StringBuffer object, to append your input
//StringBuffer is thread safe, so I prefer using it
//you could use StringBuilder if you don't expect your code to run
//in a multithreaded environment
StringBuffer output = new StringBuffer("");
//iterate over every entry in map
for (Map.Entry<String, Integer> entry : compressMap.entrySet()) {
//append the results to output
output.append(entry.getValue()).append(entry.getKey());
}
//print the output on console
System.out.println(output);
}
}
class Solution {
public String toFormat(String input) {
char inChar[] = input.toCharArray();
String output = "";
int i;
for(i=0;i<input.length();i++) {
int count = 1;
while(i+1<input.length() && inChar[i] == inChar[i+1]) {
count+=1;
i+=1;
}
output+=inChar[i]+String.valueOf(count);
}
return output;
}
public static void main(String[] args) {
Solution sol = new Solution();
String input = "aaabbbbcc";
System.out.println("Formatted String is: " + sol.toFormat(input));
}
}
def encode(Test_string):
count = 0
Result = ""
for i in range(len(Test_string)):
if (i+1) < len(Test_string) and (Test_string[i] == Test_string[i+1]):
count += 1
else:
Result += str((count+1))+Test_string[i]
count = 0
return Result
print(encode("ABBBBCCCCCCCCAB"))
If you want to get the correct count considering the string is not in alphabetical order. Sort the string
public class SquareStrings {
public static void main(String[] args) {
SquareStrings squareStrings = new SquareStrings();
String str = "abbccddddbd";
System.out.println(squareStrings.manipulate(str));
}
private String manipulate(String str1) {
//convert to charArray
char[] charArray = str1.toCharArray();
Arrays.sort(charArray);
String str = new String(charArray);
StringBuilder stbuBuilder = new StringBuilder("");
int length = str.length();
String temp = "";
if (length > 1) {
for (int i = 0; i < length; i++) {
int freq = 1;
while (((i + 1) < length) && (str.charAt(i) == str.charAt(i + 1))) {
++freq;
temp = str.charAt(i) + "" + freq;
++i;
}
stbuBuilder.append(temp);
}
} else {
return str + "" + 1;
}
return stbuBuilder.toString();
}
}
Kotlin:
fun compressString(input: String): String {
if (input.isEmpty()){
return ""
}
var result = ""
var count = 1
var char1 = input[0]
for (i in 1 until input.length) {
val char2 = input[i]
if (char1 == char2) {
count++
} else {
if (count != 1) {
result += "$count$char1"
count = 1
} else {
result += "$char1"
}
char1 = char2
}
}
result += if (count != 1) {
"$count$char1"
} else {
"$char1"
}
return result
}

putIfAbsent always returning null

I am working on a wordcount program, where I create N threads, and each thread receives a char[] buffer containing many different numbers like [2355 3326 94438 123 123...] I want to create a map where the key is the number itself, and the value is how many time it appears. I am converting from the char[] array to an integer as shown below.
However it seems that every time I call putIfAbsent(), it always returns null, meaning it did not find a key of that value. This does not make sense, as I have thousands of duplicate values in my text file. The map should end up being around 300kb, instead it is more than a gigabyte.
newbyte[] is a char[] containing ONLY numbers and spaces
Why does putIfAbsent always return null?
Also, when I print the map when finished, it looks like this:
233303192 = 1
1770057208 = 1
1323329638 = 1
1278321050 = 1
962422124 = 1
472527478 = 1
936125441 = 1
-350637153 = 1
-601349585 = 1
Which is quite odd, because the largest value of any input is 65535. Not sure how this makes any sense.
public void run() {
int counter = 0; int i; Integer check; int j =0; int temp = 0; int intbuilder = 0;
for (i = 0; i < newbyte.length; i++) {
if (newbyte[i] != ' ') { //delimiter is not found, so add to temp char array
intbuilder = (intbuilder * 10) + (int)newbyte[i];
counter++;
}
else {
check = wordCountMap.putIfAbsent(intbuilder, 1);
if (check != null) {
wordCountMap.put(intbuilder, check + 1);
}
intbuilder = 0;
The problem is not in the concurrent hash map. Its with the way you parse the character array
public void startThreads() throws InterruptedException{
char[] input = {'1',' ','2',' ','3','4',' ','1',' ','2',' ','3','4',' ','1'};
Thread workerThread = new Thread(new Worker(input));
workerThread.start();
workerThread.join();
System.out.println("Count for 1 & 2 are "+countMap.get(1)+" and "+countMap.get(2));
}
private class Worker implements Runnable{
private char[] newbyte;
public Worker(char[] newbyte){
this.newbyte = newbyte;
}
#Override
public void run() {
int number=0;
for(int i=0;i< newbyte.length;i++){
if(newbyte[i] != ' '){
number = (number*10)+Character.getNumericValue(newbyte[i]);
}else{
Integer currentValue = countMap.putIfAbsent(number, 1);
if(currentValue != null){
countMap.put(number, currentValue+1);
}
number = 0;
}
}
Integer currentValue = countMap.putIfAbsent(number, 1);
if(currentValue != null){
countMap.put(number, currentValue+1);
}
}
}

Categories

Resources