How can a number triangle come out of this code? - java

I'm a beginner in java and this code was used in a book I'm reading, however I can't seem to figure out how it works.
The code:
public class NumberTriangleWhile {
public static void main(String[] args) {
int number = 0;
String output = "";
while (number < 10) {
output = output + number;
System.out.println(output);
number++;
}
}
}
The output:
0
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789
I don't understand why each number is printed and then somehow stored and reused in the next line, can someone explain this please?

output is a string variable. When you add something to it like this:
output = output + number;
It does not add the numerical value of the number, but instead just joins the number with the original string. For example, if output was originally 1 and number is 2, the above line will change output to 12, not 3.
The loop keeps looping until number is 10. In the first iteration, output changed from an empty string to 0. In the second iteration (number has now increased to 1), output changed to 01 (the original 0 joined with the current value of number - 1). In the third iteration, number is incremented to 2. 2 is then added to the end of output to form 012. This carries on until number is 10.
The misconception you have might be that you think output becomes empty after you print it. It does not. It will still hold the same value.

In every step inside while loop, output added with number, in Java adding something with String will result in String for example:
String str = "a" + 2;
results in str="a2";.
If we start our loop, in first step number = 0 and output="" hence output = "" + 0 that make output = "0" in second run number=1 hence output = "0" (Old output value) + 1 that make output = "01" and so on

The string output is defined outside of the while loop. It can be read from and written to inside of the while loop and its contents will be consistent in the next iteration.
If output would be defined inside of the while loop, for example:
while ( number < 10) {
String output = "";
output += number;
}
then your output would just be (with new line after each number)
0
1
2
3
4
5
6
7
8
9
Since the new number is consistent throughout each iteration of the while loop, it is "stored" as you say

Each number is getting printed because its getting concatenated.
When number=0,
And you are storing the value of number into the output as:
Output=output+number
Then the number which is an integer gets stored as a string in the output
Each time the loop runs the new incremented number gets concatenated with the previous value in the string output.
That's why all numbers are getting printed each time.
make this change in your code and you'll get your output
public static void main(String[] args)
{
int number=0;
String output="";
while(number <10)
{
output=output+number;
System.out.println(output);
number++;
output="";
}
}

Related

Hashmap in for loop not reading all the input

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");
}

Java - getting and using the integers from an array (0-how ever many the user inputted)

My program requires an input of as many integers as the user wishes on a SINGLE line. My program must then, take the first integer the user entered decide if it is in the range or not. If NOT output error, If YES then do specified conversion. THEN move to the SECOND integer entered by the user (if there is one).
The way I have tackled this so far is this...
System.out.print("Enter a digit(s). ");
//Gets input numbers and stores them as a whole string
//e.g if enters 1 2 3 input will = "1 2 3"
String input = kbd.nextLine();
//Splits the input at every space and stores them in an array
//e.g If input = "1 2 3", numbers {"1", "2", "3"}
String[] numbersString = input.split(" ");
//Creates an array the same length as our String array
//How we will store each number as an integer instead of a string
int[] numbers = new int[numbersString.length];
//a loop that goes through the array as a string
for ( int i = 0; i < numbersString.length; i++ )
{
// Turns every value in the numbersString array into an integer
// and puts it into the numbers array.
numbers[i] = Integer.parseInt(numbersString[i]);
}
My problem is that I don't know how to GET the first integer entered and then on to the second and so on... (I DONT UNDERSTAND HOW to access the array of integers ive obtained from the user and manipulate them from 1 - how ever many entered.
You access the array in a similar way to how you built it. For example, to print out the array, you can do this:
for ( int i = 0; i < numbers.length; i++ )
{
System.out.println(numbers[i]);
}
Note how the for loop is nearly identical to the last for loop in the code you posted. The only difference is numbers.length since you want to iterate over the numbers array.
You should also take the time to learn about the enhanced for loop which makes iterating over an array much easier.
What about something like this:
for(int number : numbers) //iterates through each number in the array of numbers
{
if(number > 4 && number < 10) //or whatever range you wanted
{
number *= 2; //or whatever conversion you wanted
System.out.println(number);
}
}
This uses an enhanced for loop as mentioned in comment above. The variable number (singular) is each int in your array of numbers.

Out of Bounds Exception on a 2D Ragged Array in Java

Problem solved, I ended up need a seperate counter for the array position. Thanks for the help!
I'm writing a small app that takes a string, processes each string into 7-bits of binary code and then fills in a musical scale based on the string. For instance, if I had the binary 1000100, in the key of C Major that would give me the notes C and G(C 0 0 0 G 0 0).
I'm having an issue with a specific piece of code that takes an input of String[] (in which each element is a single character worth of binary, 7-bits) and processes each individual character in the strings themselves and stores the index number of where 1's occur in the string. For example, the string 1000100 would output 1 and 5.
Here's the method that does that:
public static String[][] convertToScale(String[] e){
String[][] notes = new String[e.length][]; //create array to hold arrays of Strings that represent notes
for(int i = 0; i < e.length; i++){
notes[i] = new String[findOccurancesOf(e[i])]; //create arrays to hold array of strings
for(int x = 0; x < e[i].length(); x++){
if((e[i].charAt(x)) != 48){ //checks to see if the char being evaluated is 0(Ascii code 48)
notes[i][x] = Integer.toString(x + 1); // if the value isn't 0, it fills in the array for that position.the value at x+1 represents the position of the scale the note is at
}
}
}
return notes;
}
Here is the code that is uses to get the occurrences of 1 in e[1]:
public static int findOccurancesOf(String s){
int counter = 0;
for(int i = 0; i < s.length(); i++ ) {
if( s.charAt(i) == 1 ) {
counter++;
}
}
return counter;
}
The issue I'm having is with the convertToScale method. When using "Hello world" as my input(the input gets converted into 7-bit binary before it gets processed by either of these methods) it passes through the 2nd for-each loop just fine the first time around, but after it tries to fill another spot in the array, it throws
java.lang.ArrayIndexOutOfBoundsException: 3
EDIT:It occurs in the line notes[i][x] = Integer.toString(x + 1); of the convertToScale method. I've run the debugger multiple times through after trying the proposes changes below and I still get the same error at the same line. The findOccurancesOf method returns the right value(When evaluating H(1001000) it returns 2.) So the thing that confuses me is that the out of bounds exception comes up right when it fills the 2nd spot in the array.
Also, feel free to tell me if anything else is crazy or my syntax is bad. Thanks!
In findOccurancesOf():
if( s.charAt(i) == 1 ) { should be if( s.charAt(i) == '1' ) { to check for the character '1'.
Otherwise it's looking for the character with ASCII value 1.
There is an out of bounds exception because if findOccuranceOf() returns the wrong value, then notes[i] is not constructed with the correct length in the following line of convertToScale():
notes[i] = new String[findOccurancesOf(e[i])];
In addition, you probably want to use something like:
notes[i][c++] = Integer.toString(x + 1);
with some counter c initialized to 0, if I understand your intentions correctly.
The reason for AIOOBE lies in this line:
notes[i] = new String[findOccurancesOf(e[i])]; //create arrays to hold array of strings
Where you call findOccurancesOf method to find occurance of 1 in your String say Hello which you dont find and return 0 and then you call notes[i][x] = Integer.toString(x + 1); with x as 0. Now since you never allocated space, you get array index out of bound exception.
I would suggest the folowing:
Validate your string before assigning the index say to be greater than 0 or something.
Initialize you notes[i] as notes[i] = new String[e[i].length];
Checking character with single quotes like a == '1' rather than a == 1
The exception is caused by what almas mentioned, note however, that your logical error is most likely inside findOccurencesOf method, if the idea was to find all the '1' chars inside a string you must change to what I outlined below, note the apostrohes. Otherwise a char is getting converted to a byte ascii code, and unless matched with a code of ascii code one, the method will return 0, causing your exception
if( s.charAt(i) == '1' ) {

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.

Array Index Out OfBounds Help (Java)

This Java program does a simple computation and it is suppose to output the numerical value of 123+1
(The output should be 124.) (Ignore the last "+" string.)
I got an error inside the if statement:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
I did a printout for arrayz[i-1] and arrayz[i+1] and it seems to printout 123 and 1 receptively, which is correct. So, I'm not sure what's wrong.
String math = "123+1+";
String arrayz[]={"123","+","1","+"};
double total =0.0;
int i=0;
while(i<=(math.length()-1)) //don't bother with the last char
{ i++;
if(arrayz[i].equals("+"))
{
total = Double.parseDouble((String)arrayz[i-1]) + Double.parseDouble((String)arrayz[i+1]);
}
}
System.out.println(total);
while(i<=(math.length()-1))
math length is 6 and and in side loop your array length is 4
You might want to write
while(i<=(arrayz.length-1))
Since you are using the index i with the array arrayz, you must use arrayz.length instead of math.length()
Edit
This should work:
public static void main(String[] args)
{
String math = "123+1+";
String arrayz[] = { "123", "+", "1", "+" };
double total = 0.0;
int i = 0;
// arrayz.length - 2 -> because you are accessing "arrayz[i + 1]",
// arrayz.length - 1 would be OK if the maximum index you were using were "arrayz[i] "
while (i <= (arrayz.length - 2)) //don't bother with the last char
{
if (arrayz[i].equals("+")) {
total = Double.parseDouble((String) arrayz[i - 1]) + Double.parseDouble((String) arrayz[i + 1]);
}
i++; // Increment at the end of the loop
}
System.out.println(total);
}
You are looping over the string math, at the same time accessing elements of arrayz inside your loop, and thinking that they have the same elements and the same length.
What I suggest you, is to use instead of math String (you can omit it in this case but I assume you can't in general for some criteria), you can use an array of type String, so that 123 in your example would be the first element arrayz[0].

Categories