How to make a frequency histogram in java - java

I am trying to create a code that reads through a file and prints out the following:
number of lines of the file
the frequency of each letter
the frequency of each non-alphabetic character
I want to create a histogram for the frequency of the letters and numbers but I can't seem to find a solution around it. If anything i would want the output to look like this:
A ***** - 5
B *** - 3
C ******* - 7
My output looks like this:
*********************
*********************
*********************
A 263
B 130
C 50
etc.

This is how you do the task. It counts the number of lower case letters and prints the stars as well in addition to the frequency, just as you wanted.
Here is the general code (paragraph is the string that contains the content of your file):
int[] lettercount = new int[26];
for(int i = 0; i < 26; i++){
//Set every single number in the array to 0.
lettercount[i] = 0;
}
for(char s : paragraph.toCharArray()){
int converted = (int) s;
converted -= 97;
if(converted >=0 && converted <=25){
lettercount[converted] += 1;
}
}
//Print out the letter with the frequencies.
for(int i = 0; i < 26; i++){
char convertback = (char) (i+97);
String stars = "";
for(int j = 0; j < lettercount[i]; j++){
stars += "*";
}
System.out.println(convertback + " " + stars + " - " + lettercount[i]);
}
This should work for lowercase letters. If you want to do uppercase letters, lettercount[] should be 52 elements long. You would also have to check if converted (in the second for loop), after subtracting 97 is negative, and if it is, you would add back 58.
I hope this helps! If you have any problems, just comment below.

Related

How would I add two int that are in the same array to each other and convert them into an int. In the Luhn Algorithm

I am trying to add two parts of an array together to go into an int value. I am using Luhn algorithm to figure out of a credit card is a valid credit card. We are only using 6 digit credit card's just to make sure no one enter's a real credit card number. The part I am confused on is when I go to split a number that is above 10 and add it together. Example if the algorithm was to give me 12 I would need to separate it into 1 and 2 and then add them together to equal 3. I believe I am splitting it currently in the code but when I go to add them together I get some number that makes no since. here is a section of the code with some notes about it.
I have printed out numbers in certain places to show myself what is going on in certain places. I have also added in some comments that say that either the number that is printed out is what is expected, and some comments for when there isn't something I expected
int[] cardNumber = new int[]{ 1,2,3,4,5,5};
int doubleVariablesum = 0;
int singleVariablesum = 0;
int totalSum = 0;
int cutOffVar = 0;
String temp2;
for (int i = cardNumber.length - 1; i >= 0;) {
int tempSum = 0;
int temp = cardNumber[i];
temp = temp * 2;
System.out.println("This is the temp at temp * 2: " + temp);
temp2 = Integer.toString(temp);
if (temp2.length() == 1) {
System.out.println("Temp2 char 0: "+ temp2.charAt(0));
// this prints out the correct number
// Example: if there number should be 4 it will print 4
tempSum = temp2.charAt(0);
System.out.println("This is tempSum == 1: " + tempSum);
// when this goes to add temp2.charAt(0) which should be 4 it prints out //something like 56
} else {
System.out.println("TEMP2 char 0 and char 1: " + temp2.charAt(0) + " " + temp2.charAt(1));
// this prints out the correct number successfully spited
tempSum = temp2.charAt(0) + temp2.charAt(1);
System.out.println("This is tempSum != 1: " + tempSum);
// but here it when I try to add them together it is giving me something
// like 97 which doesn't make since for the numbers I am giving it
}
doubleVariablesum = tempSum + doubleVariablesum;
System.out.println("This is the Double variable: " + doubleVariablesum);
System.out.println();
i = i - 2;
}
Since you are converting the number to a string to split the integer, and then trying to add them back together. You're essentially adding the two characters numerical values together which is giving you that odd number. You would need to convert it back to an integer, which you can do by using
Integer.parseInt(String.valueOf(temp2.charAt(0)))
When adding char symbols '0' and '1' their ASCII values are added - not numbers 0 and 1.
It is possible to use method Character::getNumericValue or just subtract '0' when converting digit symbol to int.
However, it is also possible to calculate sum of digits in a 2-digit number without any conversion to String and char manipulation like this:
int sum2digits = sum / 10 + sum % 10; // sum / 10 always returns 1 if sum is a total of 2 digits
Seems like charAt() type casts into integer value, but the ascii one. Hence for the characters '0' and '1', the numbers 48 and 49 are returned resulting in a sum of 97. To fix this, you could just assign temp2 to (temp / 10) + (temp % 10). Which actually splits a two digit integer and adds their sum.
You need to be aware of the following when dealing with char and String
Assigning the result of charAt(index) to an int will assign the ASCII value and not the actual integer value. To get the actual value you need to String.valueOf(temp2.charAt(0)).
The result of concatenating chars is the sum of the ASCII values.
eg if char c = '1'; System.out.println(c + c); will print "98" not "11".
However System.out.println("" + c + c); will print "11". Note the "" will force String concatenation.

Get input from user and print decreasing pattern of numbers

Can someone help me write a code that prints the following pattern.
987654321
98765432
9876543
987654
98765
9876
987
98
9
This is my code sample but I am getting the exact opposite of the above pattern.
height = getInPut("Enter the height of the triangle");
int h = Integer.parseInt(height);
int start = h, num=1,max=h;
for (int r= 1; r <=h; r++)
{
System.out.println();
for (int j = 1; j<= max; j++)
{
if(h>=6 && h<=10)
{
System.out.print(num);
}else{
System.out.println("height should be between 6-10");
System.exit(0);
}
num++;
}
num= r+1;
max--;
}
I would start with an initial value of 987654321 in a StringBuilder, then loop while that contains characters; in every iteration of the loop, we want to print the difference (in spaces) between the initial length (nine) and the current length of the StringBuilder, then print the contents of the StringBuilder before removing the last character. Like,
StringBuilder sb = new StringBuilder("987654321");
while (sb.length() > 0) {
for (int i = 0; i < 9 - sb.length(); i++) {
System.out.print(' ');
}
System.out.println(sb);
sb.setLength(sb.length() - 1);
}
Which outputs (as requested)
987654321
98765432
9876543
987654
98765
9876
987
98
9
I'll leave filling the initial StringBuilder and adjusting nine into a variable as an exercise for the reader.

Formatting with Array[i] Logic

I'm trying to build a program that prints 75 random caps and lowercase letters, 25 per line. I think I have all the logic worked out, but whenever I run it the formatting is all off and rather than printing 25 characters per line, it prints a random number. Here's my code so far:
char allLetters[] = new char[3700];
for(int i = 1; i <= 75; i++) { //Begin for loop
int max = 122;
int min = 65;
allLetters[i] = (char)(Math.random() * (max - min) + min);
if(i % 25 != 0){
if (allLetters[i] <= 90) {
System.out.printf("%s,",allLetters[i]);
}
if (allLetters[i] >= 97) {
System.out.printf("%s,",allLetters[i]);
}
} //Close if
else {
if (allLetters[i] <= 90) {
System.out.printf("%s\n",allLetters[i]);
}
if (allLetters[i] >= 97) {
System.out.printf("%s\n",allLetters[i]);
}
}
} //End for
Currently, the output is something like:
U,i,y,e,v,T,G,p,P,a,U,G,e,B,w,U,o,F,G,w,j,m,R
O,X,w,w,u,p,t,g,X,J,R,c,w,I,d,H,R,m,y,b,o
C,p,M,F,X,U,v,O,a,Y,F,E,x,s,x,k,C,b,D,R,r,H
I've tried using different variables besides i, playing around with numbers and such but I can't seem to find the exact flaw in the logic that throws the formatting off. Any help would be greatly appreciated!
The problem with your logic is that you are counting each chosen character even when you do not print it. The ASCII characters falling between 90 and 97, exclusive, are not characters, and you rightfully skip printing them. Yet the loop is still counting those iterations as if a valid letter has been printed. This is resulting in an incorrect count in the output.
The workaround used in the code snippet below is to keep picking characters in a loop until we actually get a lowercase or uppercase letter. Only then do we continue with your previous logic.
char allLetters[] = new char[3700];
int max = 122;
int min = 65;
for (int i = 1; i <= 75; i++) {
char next;
do {
next = (char)(Math.random() * (max - min) + min);
} while (next > 90 && next < 97);
allLetters[i] = next;
if (i % 25 != 0) {
System.out.printf("%s,", next);
}
else {
System.out.printf("%s\n", next);
}
}
Demo
Your two conditions that you put on your random characters, namely allLetters[i] <= 90 and allLetters[i] >= 97, do not cover the entire interval of possible characters, which in your program is 65 to 122, inclusive. When a character between 91 and 96 gets generated, your program does not print anything. The probability of getting one of these six random characters is roughly 10%, so you get 21..23 characters printed.
If you really want to skip these six characters, fix the problem by using a while loop instead of a for loop, and increment the counter of printed characters only when you print something:
int printed = 0;
while (printed != 75) {
char ch = (char)(Math.random() * (max - min) + min);
if (ch >= 91 && ch <= 96) continue;
printed++;
System.out.print(ch);
if (printed % 25 == 0 {
System.out.println();
} else {
System.out.print(',');
}
}
I was looking at your problem, and there's a "clever" solution using Java 8+ IntStream and lambdas. Generate 75 random int(s) between 0 and 26, map each value to a one-character String offset from either 'a' or 'A' by using nextBoolean() from Random. Collect that to a single seventy-five character String. Then print the three twenty-five character substring(s) we're interested in. Like,
Random rand = new Random();
String s = IntStream.generate(() -> rand.nextInt(26)).limit(75)
.mapToObj(i -> Character.toString(
rand.nextBoolean() ? (char) (i + 'a') : (char) (i + 'A')))
.collect(Collectors.joining());
System.out.println(s.substring(0, 25));
System.out.println(s.substring(25, 50));
System.out.println(s.substring(50));

Print horizontal histogram for letters in file. How to scale it? Java

I would like to count the occurences of letters in a text file and draw a horizontal histogram. However, the longest bar should have the length of 50 stars. It's not a problem, when I have, the number less than 50, but how to scale it so I have everything on a histogram?
I came up with this formula: 50 - 50 * histogram[i] / maxnum where 50 is the maximum length of the bar, histogram[i] is the number of occurences of the i-th letter in an alphabet and maxnum is the number representing the number of occurences of the most common letter in my file.
int[] histogram = new int[26];
String alphabeth = "abcdefghijklmnopqrstuvwxyz";
Here's how I build the histogram:
while((line = bfr.readLine()) != null){
for (int i =0;i< line.length();i++){
int index = alphabeth.indexOf(line.charAt(i));
if (index != -1)
histogram[index]++;
}
}
I look for the maxval:
int maxnum = histogram[0];
for (int p=1; p<histogram.length;p++){
if (maxnum < histogram[p]){
maxnum = histogram[p];
}
}
And that's how I draw it:
for (int i=0; i<alphabeth.length(); i++){
System.out.print(alphabeth.charAt(i) + " ");
int count = histogram[i];
for (int k=0; k<50-50*histogram[i]/maxval; k++){
System.out.print("*");
}
}
Is it right?
I don't see an sense in the 50-50. Can't you just remove the first 50?
Is histogram[i] or maxval of type float or double? This would be needed for the division to not return an integer value.
Btw: You should really used brackets in your formula. And it might be a good idea to calculate the number of stars to print seperately and store it in a separate variable and not calculating it within the header of the for loop.
The issue with your 50 logic is that it skews the look of the data when a char does occur 50 times and all others don't. If you use a percent, your data will make sense in the histogram no matter the number of occurrences of one character. Below is some code I used to create a basic histogram that outputs the number of stars based on the percentage
HashMap<Integer, Integer> alphabet = new HashMap<>();
double totalChars = 0;
for(int i = 0; i < 26; i++)
{
Random ran = new Random();
int x = ran.nextInt(500) + 1; //create some random amount of char occurrences
alphabet.put(i, x);
totalChars += alphabet.get(i); //get the total char count
}
System.out.println("Total Chars: " + totalChars);
for(int i = 0; i < 26; i++)
{
System.out.print(i + " [" + ((double)alphabet.get(i))/totalChars * 100 + "%]: ");
for(int j = 0; j < ((double)alphabet.get(i))/totalChars * 100; j++)
{
System.out.print("*");
}
System.out.println();
}
Every run of the program it generates random occurrences so you can see how the historgram behaves and looks based on percents.
Output:
Total Chars: 6898.0
0 [6.494636126413453%]: *******
1 [2.7544215714699916%]: ***
2 [3.0878515511742535%]: ****
3 [3.1603363293708324%]: ****
4 [4.914467961728037%]: *****
5 [1.7396346767178894%]: **
6 [0.8408234270803132%]: *
7 [4.450565381269933%]: *****
8 [3.102348506813569%]: ****
9 [1.0872716729486807%]: **
10 [6.668599594085242%]: *******
11 [7.060017396346767%]: ********
12 [3.0878515511742535%]: ****
13 [5.131922296317773%]: ******
14 [1.348216874456364%]: **
15 [5.131922296317773%]: ******
16 [2.638445926355465%]: ***
17 [1.290229051899101%]: **
18 [3.4067845752391994%]: ****
19 [1.6526529428819947%]: **
20 [7.089011307625398%]: ********
21 [6.364163525659612%]: *******
22 [5.682806610611771%]: ******
23 [5.769788344447666%]: ******
24 [5.030443606842563%]: ******
25 [1.0147868947521022%]: **

Output of converting string into number does not come as expected

Given a string as input, convert it into the number it represents. You can assume that the string consists of only numeric digits. It will not consist of negative numbers. Do not use Integer.parseInt to solve this problem.
MyApproach
I converted string to char array and stored the original number but I am unable to convert it into a single number
I tried converting individual elements but the digits can be of any length.So,It was difficult to follow that approach.
Hint:I have a hint that the numbers can be added using place values
For e.g if the number is 2300.I stored each number in the form of arrays.Then it should be 2*1000+3*100+0*10+0=2300
But I am unable to convert it into code.
Can anyone guide me how to do that?
Note I cannot use any inbuilt functions.
public int toNumber(String str)
{
char ch1[]=str.toCharArray();
int c[]=new int[ch1.length];
int k=0;
for(int i=0;i<c.length;i++)
{
if(ch1[i]==48)
{
c[k++]=0;
}
else if(ch1[i]==49)
{
c[k++]=1;
}
else if(ch1[i]==50)
{
c[k++]=2;
}
else if(ch1[i]==51)
{
c[k++]=3;
}
else if(ch1[i]==52)
{
c[k++]=4;
}
else if(ch1[i]==53)
{
c[k++]=5;
}
else if(ch1[i]==54)
{
c[k++]=6;
}
else if(ch1[i]==55)
{
c[k++]=7;
}
else if(ch1[i]==56)
{
c[k++]=8;
}
else if(ch1[i]==57)
{
c[k++]=9;
}
}
}
You don't need to do powers or keep track of your multiplier. Just multiply your running total by 10 each time you add in a new digit. And use c - '0' to turn a character into a number:
int n = 0;
for (int i = 0; i < str.length(); i++) {
n = n * 10 + str.charAt(i) - '0';
}
So for example for 1234 it goes
0 * 10 + 1 = 1
1 * 10 + 2 = 12
12 * 10 + 3 = 123
123 * 10 + 4 = 1234
A digit character ('0'-'9') can be converted into an integer value (0-9) using:
ch - '0'
This is because the digit characters are all consecutive in ASCII/Unicode.
As for calculating the full number, for the input 2300, you don't want:
2 * 1000 + 3 * 100 + 0 * 10 + 0
Instead, you'll want a more incremental approach using a loop:
r = 0
r = r * 10 + 2 (2)
r = r * 10 + 3 (23)
r = r * 10 + 0 (230)
r = r * 10 + 0 (2300)
This is much better than trying to calculate 1000 (Math.pow(10,3)), which your formula would require.
This should be enough information for you to code it. If not, create a new question.
If you loop through the char array you have and take the last value, put it through an if statement and add to an to number integer whatever that number is (use 10 if statements). Next go to the second to last value, and do the same thing only this time multiply the resulting numbers by 10 before adding it to the total number. Repeat this using 1 * 10^(value away from end) being multiplied to the number gotten from the if statements.
Well what comes to my mind when seeing this problem is to multiply the numbers you are getting with your current code with the place they have in the charArray:
int desiredNumber = 0;
for(int k=1; k<=c.length; k++) {
desiredNumber += c[k] * (Math.pow(10, c.length - k));
}
If you are not allowed to use the Math.pow() function then simply write one yourself with aid of a loop.
Greetings Raven
You can do
int no = 0;
for(int i = 0; i < c.length; i++){
no += c[i] * Math.pow(10, c.length - 1 - i);
}

Categories

Resources