Hashmap in for loop not reading all the input - java

This is for AOC day 2. The input is something along the lines of
"6-7 z: dqzzzjbzz
13-16 j: jjjvjmjjkjjjjjjj
5-6 m: mmbmmlvmbmmgmmf
2-4 k: pkkl
16-17 k: kkkkkkkkkkkkkkkqf
10-16 s: mqpscpsszscsssrs
..."
It's formatted like 'min-max letter: password' and seperated by line. I'm supposed to find how many passwords meet the minimum and maximum requirements. I put all that prompt into a string variable and used Pattern.quote("\n") to seperate the lines into a string array. This worked fine. Then, I replaced all the letters except for the numbers and '-' by making a pattern Pattern.compile("[^0-9]|-"); and running that for every index in the array and using .trim() to cut off the whitespace at the end and start of each string. This is all working fine, I'm getting the desired output like 6 7 and 13 16.
However, now I want to try and split this string into two. This is my code:
HashMap<Integer,Integer> numbers = new HashMap<Integer,Integer>();
for(int i = 0; i < inputArray.length; i++){
String [] xArray = x[i].split(Pattern.quote(" "));
int z = Integer.valueOf(xArray[0]);
int y = Integer.valueOf(xArray[1]);
System.out.println(z);
System.out.println(y);
numbers.put(z, y);
}
System.out.println(numbers);
So, first making a hasmap which will store <min, max> values. Then, the for loop (which runs 1000 times) splits every index of the 6 7 and 13 16 string into two, determined by the " ". The System.out.println(z); and System.out.println(y); are working as intended.
6
7
13
16
...
This output goes on to give me 2000 integers seperated by a line each time. That's exactly what I want. However, the System.out.println(numbers); is outputting:
{1=3, 2=10, 3=4, 4=7, 5=6, 6=9, 7=12, 8=11, 9=10, 10=18, 11=16, 12=13, 13=18, 14=16, 15=18, 16=18, 17=18, 18=19, 19=20}
I have no idea where to even start with debugging this. I made a test file with an array that is formatted like "even, odd" integers all the way up to 100. Using this exact same code (I did change the variable names), I'm getting a better output. It's not exactly desired since it starts at 350=351 and then goes to like 11=15 and continues in a non-chronological order but at least it contains all the 100 keys and values.
Also, completely unrelated question but is my formatting of the for loop fine? The extra space at the beginning and the end of the code?
Edit: I want my expected output to be something like {6=7, 13=16, 5=6, 2=4, 16=17...}. Basically, the hashmap would have the minimum and maximum as the key and value and it'd be in chronological order.

The problem with your code is that you're trying to put in a nail with a saw. A hashmap is not the right tool to achieve what you want, since
Keys are unique. If you try to input the same key multiple times, the first input will be overwritten
The order of items in a HashMap is undefined.
A hashmap expresses a key-value-relationship, which does not exist in this context
A better datastructure to save your Passwords would probably just be a ArrayList<IntegerPair> where you would have to define IntegerPair yourself, since java doesn't have the notion of a type combining two other types.

I think you are complicating the task unnecessarily. I would proceed as follows:
split the input using the line separator
for each line remove : and split using the spaces to get an array with length 3
build from the array in step two
3.1. the min/max char count from array[0]
3.2 charachter classes for the letter and its negation
3.3 remove from the password all letters that do not correspond to the given one and check if the length of the password is in range.
Something like:
public static void main(String[] args){
String input = "6-7 z: dqzzzjbzz\n" +
"13-16 j: jjjvjmjjkjjjjjjj\n" +
"5-6 m: mmbmmlvmbmmgmmf\n" +
"2-4 k: pkkl\n" +
"16-17 k: kkkkkkkkkkkkkkkqf\n" +
"10-16 s: mqpscpsszscsssrs\n";
int count = 0;
for(String line : input.split("\n")){
String[] temp = line.replace(":", "").split(" "); //[6-7, z, dqzzzjbzz]
String minMax = "{" + (temp[0].replace('-', ',')) + "}"; //{6,7}
String letter = "[" + temp[1] + "]"; //[z]
String letterNegate = "[^" + temp[1] + "]"; //[^z]
if(temp[2].replaceAll(letterNegate, "").matches(letter + minMax)){
count++;
}
}
System.out.println(count + "passwords are valid");
}

Related

How to add text to a textfield without overriding the current text?

I have a program where it asks the user for how many numbers to be sorted then randomly generates the amount of numbers the user asks and sorts it. This is my first attempt at using swing on java so im not sure how to go about one of my features. When the user press's sort there are 2 text fields. One is the array of the unsorted numbers and the other field will be where the sorted numbers go. However when I enter the amount of numbers then press sort I should expect the numbers with a comma. Maybe im using the wrong command for the text field but I cant figure it out. I think only the last number is coming up and is the only one that appears.
//get data
String data = txtInput.getText();
//parse for numerical value
int numGenerate = Integer.parseInt(data);
int Numbers[]=new int[numGenerate];
for (int x=0;x<=Numbers.length-1;x++)
{
Numbers[x]=(int)(Math.random()*1000)+1;
txtUnsorted.setText(String.valueOf(Numbers[x])+",");
}
Try this one.
txtUnsorted.setText(txtUnsorted.getText() + String.valueOf(Numbers[x])+ "," );
First of all don't name variable with a capital letter. Only classes should name with a capital letter.
Second thing, you don't have to parse int to String to print it.
In method setText you put only a number and a comma. You should also put existing value of this field:
txtUNsorted.setText(txtUnsorted.getText() + ", " + numbers[x]);
setText() method replaces the current text.
So get first txtUnsorted.getText() then assign to variable. Use setText() afterwards.
var unsorted = txtUnsorted.getText();
txtUnsorted.setText(unsorted + String.valueOf(Numbers[x])+",");
As czachodym said don't begin a variable with an Uppercase letter. Go through this Java Document to see the rules and conventions for naming your variables.
And also I don't think you need this statement like this because Arrays are zero-based,
x <= Numbers.length - 1
Just change above to the following because following is the correct way to iterate through an array,
x < Numbers.length
So your entire code should be like this,
// get data
String data = txtInput.getText();
// parse for numerical value
int numGenerate = Integer.parseInt(data);
int Numbers[] = new int[numGenerate];
for (int x = 0; x < Numbers.length; x++)
{
Numbers[x] = (int)(Math.random() * 1000) + 1;
txtUnsorted.setText(Numbers[x] + "," + txtUnsorted.getText()); // or
txtUnsorted.setText(txtUnsorted.getText() + Numbers[x] + ",");
}

Single characters don't left-justify using format in Java?

A problem I'm having in my programming class is asking me to make a pattern like this:
I used the following code:
public static void ch5ex18c() {
System.out.println("Pattern C");
String num = "6 5 4 3 2 1";
for (int count = 10; count >= 0; count-=2){
System.out.printf("%-10s", num.substring(count, 11) + "\n");
}
}
and I got everything to print out well except the first number line:
I know I can fix this using an if statement, but I'd just prefer not to and I want to know why it would do this in the first place.
The problem is that your new lines are inserted before extra spaces ("1\n" + spaces), you need to remove the minus sign (that justifies left) and make some minor math alterations.
1\n spaces (shown on next line to make it seem like your justifying right
2 1\n spaces
and so on

Find the letter that occur most times from user with using tables [duplicate]

This question already has answers here:
Java program to find the character that appears the most number of times in a String?
(8 answers)
Closed 6 years ago.
I got a task from my university today:
Write a program that reads a ( short ) text from the user and prints the so called max letter (most common character in string) , that the letter which the greatest number of occurrences of the given text .
Here it is enough to look at English letters (A- Z) , and not differentiate between uppercase and lowercase letters in the count of the number of occurrences .
For example, if : text = " Ada bada " so should the print show the most common character, this example it would be a.
This is an introductory course, so in this submission we do not need to use the " scanner - class" . We have not gone through this so much.
The program will use the show message input two get the text from user .
Info: The program shall not use while loop ( true / false ) , "return " statement / "break " statement .
I've been struggling with how I can get char values into a table.. am I correct I need to use array to search for most common character? I think I need to use the binarySearch, but that only supports int not char.
I'll be happy for any answers. hint's and solutions. etc.. if you're very kind a full working program, but again please don't use the things I have written down in the "info" section above.
My code:
String text = showInputDialog("Write a short text: ");
//format string to char
String a = text;
char c = a.charAt(4);
/*with this layout it collects number 4 character in the text and print out.
* I could as always go with many char c... but that wouldn't be a clean program * code.. I think I need to make it into a for-loop.. I have only worked with * *for-loops with numbers, not char (letters).. Help? :)
*/
out.print( text + "\n" + c)
//each letter into 1 char, into table
//search for most used letter
Here's the common logic:
split your string into chars
loop over the chars
store the occurrences in a hash, putting the letter as key and occurrences as value
return the highest value in the hash
As how to split string into chars, etc., you can use Google. :)
Here's a similar question.
There's a common program asked to write in schools to calculate the frequency of a letter in a given String. The only thing you gotta do here is find which letter has the maximum frequency. Here's a code that illustrates it:
String s <--- value entered by user
char max_alpha=' '; int max_freq=0, ct=0;
char c;
for(int i=0;i<s.length();i++){
c=s.charAt(i);
if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){
for(int j=0;j<s.length();j++){
if(s.charAt(j)==c)
ct++;
} //for j
}
if(ct>max_freq){
max_freq=ct;
max_alpha=c;
}
ct=0;
s=s.replace(c,'*');
}
System.out.println("Letter appearing maximum times is "+max_alpha);
System.out.println(max_alpha+" appears "+max_freq+" times");
NOTE: This program presumes that all characters in the string are in the same case, i.e., uppercase or lowercase. You can convert the string to a particular case just after getting the input.
I guess this is not a good assigment, if you are unsure about how to start. I wish you for having better teachers!
So you have a text, as:
String text = showInputDialog("Write a short text: ");
The next thing is to have a loop which goes trough each letter of this text, and gets each char of it:
for (int i=0;i<text.length();i++) {
char c=text.charAt(i);
}
Then comes the calculation. The easiest thing is to use a hashMap. I am unsure if this is a good topic for a beginners course, so I guess a more beginner friendly solution would be a better fit.
Make an array of integers - this is the "table" you are referring to.
Each item in the array will correspond to the occurrance of one letter, e.g. histogram[0] will count how many "A", histogram[1] will count how many "B" you have found.
int[] histogram = new int[26]; // assume English alphabet only
for (int i=0;i<histogram.length;i++) {
histogram[i]=0;
}
for (int i=0;i<text.length();i++) {
char c=Character.toUppercase(text.charAt(i));
if ((c>=65) && (c<=90)) {
// it is a letter, histogram[0] contains occurrences of "A", etc.
histogram[c-65]=histogram[c-65]+1;
}
}
Then finally find the biggest occurrence with a for loop...
int candidate=0;
int max=0;
for (int i=0;i<histogram.length;i++) {
if (histogram[i]>max) {
// this has higher occurrence than our previous candidate
max=histogram[i];
candidate=i; // this is the index of char, i.e. 0 if A has the max occurrence
}
}
And print the result:
System.out.println(Character.toString((char)(candidate+65));
Note how messy this all comes as we use ASCII codes, and only letters... Not to mention that this solution does not work at all for non-English texts.
If you have the power of generics and hashmaps, and know some more string functions, this mess can be simplified as:
String text = showInputDialog("Write a short text: ");
Map<Char,Integer> histogram=new HashMap<Char,Integer>();
for (int i=0;i<text.length();i++) {
char c=text.toUppercase().charAt(i));
if (histogram.containsKey(c)) {
// we know this letter, increment its occurrence
int occurrence=histogram.get(c);
histogram.put(c,occurrence+1);
}
else {
// we dunno this letter yet, it is the first occurrence
histogram.put(c,1);
}
}
char candidate=' ';
int max=0;
for (Char c:histogram.keySet()) {
if (histogram.get(c)>max) {
// this has higher occurrence than our previous candidate
max=histogram.get(c);
candidate=c; // this is the char itself
}
}
System.out.println(c);
small print: i didn't run this code but it shall be ok.

length of a String with surrogate characters in it - java

I am having trouble counting the length of my String which has some surrogate characters in it ?
my String is,
String val1 = "\u5B66\uD8F0\uDE30";
The problem is, \uD8F0\uDE30 is one character not two, so the length of the String should be 2.
but when I am calculating the length of my String as val1.length() it gives 3 as output, which is totally wrong. how can I fix the problem and get the actual length of the String?
You can use codePointCount(beginIndex, endIndex) to count the number of code points in your String instead of using length().
val1.codePointCount(0, val1.length())
See the following example,
String val1 = "\u5B66\uD8F0\uDE30";
System.out.println("character count: " + val1.length());
System.out.println("code points: "+ val1.codePointCount(0, val1.length()));
output
character count: 3
code points: 2
FYI, you cannot print individual surrogate characters from a String using charAt() either.
In order to print individual supplementary character from a String use codePointAt and offsetByCodePoints(index, codePointOffset), like this,
for (int i =0; i<val1.codePointCount(0, val1.length()); i++)
System.out.println("character at " + i + ": "+ val1.codePointAt(val1.offsetByCodePoints(0, i)));
}
gives,
character at 0: 23398
character at 1: 311856
for Java 8
You can use val1.codePoints(), which returns an IntStream of all code points in the sequence.
Since you are interested in length of your String, use,
val1.codePoints().count();
to print code points,
val1.codePoints().forEach(a -> System.out.println(a));

Get Each Character From Output - Java

Right now I have a program that puts an inputted expression into Postfix Evaluation. Below is a copy of my console.
Enter an expression: ((5*2-1)/6+14/3)*(2*3-5)+7/2
5 2 * 1 - 6 / 14 3 / + 2 3 * 5 - * 7 2 / +
I now need to walk through the output, however this output is just a bunch of System.out.print 's put together. I tried using a stringBuilder however it cant tell the difference between 14 and a 1 and 4.
Is there anyway I can go through each character of this output? I need to put these numbers into a stack.
You can use String.split() and if you need only numbers regular expression.
Here is an Example:
public class Test {
public static void main(String[] args) {
String str = "1 * 2 3 / 4 5 6";
String[] arr = str.split(" ", str.length());
for (int i=0;i < arr.length;i++)
System.out.println(arr[i] + "is diggit? " + arr[i].matches("-?\\d+(\\.\\d+)?"));
}
}
str holds the long String. arr will hold the split sub strings.
you just need to make sure that each sub string differ one space from the other.
Well, you deleted your code while I was reading it, but here's a conceptually developed answer.
As you input every character, you want to push that to the stack.
The unique scenario you've mentioned 14 is unique in that it's two characters.
So what you would want to do is track if the last character was ALSO a number.
Here's a rough pseudo. Your stack should be all Strings to support this.
//unique case for digit
if(s.charAt(0).isDigit()) {
//check to see if the String at the top of a stack is a number by peeking at its first character
if(stack.peek().charAt(0).isDigit()) {
int i = Integer.parseInt(stack.pop()) * 10;
//we want to increment the entire String by 10, so a 1 -> 10
i = i + Character.getNumericValue(s.charAt(0)); //add the last digit, so 10 + 4 = 14
stack.push(Integer.toString(i)); //put the thing back on the stack
}
else {
//handle normally
stack.push(s.substring(0,1));
}
}
Is there a reason you need to parse the actual string?
If so, then what you do is, create a StringBuffer or StringBuilder, and wherever you put System.out.print in your code, append the buffer - including the spaces, which are what will help you differentiate between 1 4 and 14. Then you can convert that to a String. Then you can parse the String by splitting it by the spaces. Then iterate through the resulting String array.
If there is no reason for you to use the actual full string, you can instead use a List object and just add to it in the same places in the code. In this case, you don't need the spaces. Then you'll be able to simply iterate through the list.
You'll still be able to print you output - by printing the elements in the list.

Categories