I'm hoping someone can help me with these two values that have me stuck on a project. I have two classes and this first one generates a 2D array with random values.
import java.util.concurrent.ThreadLocalRandom;
public class Guitar {
private int strings;
private int chords;
public Guitar(int mstrings, int mchords) {
this.strings = mstrings;
this.chords = mchords;
}
private double[][] song = new double[strings][chords];
public void generateSong() {
for (int i = 0; i < song.length; i++) {
for (int j = 0; j < song[i].length; j++) {
song[i][j] = ThreadLocalRandom.current().nextDouble(27.5, 4186);
System.out.printf(" %.2f",song[i][j]);
}
System.out.println();
}
}
}
The number of rows and columns is determined by command line arguments. args[0] is the number of rows, args[1] is the number of columns. I converted them to int variables in the main method class
public class Songwriter {
public static void main(String[] args) {
System.out.println("Guitar(): Generated new guitar with " + args[0] + " strings. Song length is " + args[1] + " chords.");
String args0 = args[0];
int strings = Integer.parseInt(args0);
String args1 = args[1];
int chords = Integer.parseInt(args1);
Guitar guitarObj1 = new Guitar(strings, chords);
guitarObj1.generateSong();
}
}
My problem lies in passing the int variables of the command line arguments to make the 2D array the corresponding size. I know my code isn't completely wrong b/c when I set the strings and chords variables equal to 3 and 4 or whatever in the Guitar class itself, the table prints fine.
Sorry if I seem clueless. My class just covered the first chapter on object oriented programming and I've yet to get the fundamentals down.
This is the problematic line:
private double[][] song = new double[strings][chords];
When you create a new object of your Guitar class, the song array is initialized with whatever the values of strings and chords are at that time, which would (most probably) be 0.
Change it to this:
private double[][] song;
public Guitar(int mstrings, int mchords) {
this.strings = mstrings;
this.chords = mchords;
song = new double[mstrings][mchords];
}
EDIT : OP you just answered your own question :)
It doesn't crash but the only output is the system.out.print in the
first line of the main. I believe it's because the strings and chords
variables default to 0, making the array 0x0, and I'm failing to
change their values
Related
I'm trying to create a FileIO where random numbers are placed into a .txt file and outputted, sorted in another .txt file. I have a bubble sort code that can sort numbers & I have another code that makes a .txt file. I'm just not sure how I'd implement these 2 together.
Here's my fileIO code:
public static void main(String[] args) {
File file = new File("test.txt");
//Writes name and age to the file
try {
PrintWriter output = new PrintWriter(file);
output.println("Rober");
output.println(27);
output.close();
} catch (IOException ex) {
System.out.printf("ERROR: %s\n", ex);
}
//Reads from the file
try {
Scanner input = new Scanner(file);
String name = input.nextLine();
int age = input.nextInt();
System.out.printf("Name: %s Age %d\n", name, age);
} catch (FileNotFoundException ex) {
System.out.printf("ERROR: %s\n", ex);
}
}
And here is my bubble sort code:
public static void main(String[] args) {
Random num = new Random();
//Creating an array for 10 integers
int [] number = new int [10];
System.out.print("Random Numbers:");
/*Display the unsorted numbers in a random order.
These numbers range from 0 to 100
*/
for (int d = 0 ; d<number.length ; d++){
/* We add a "+1" to the nextInt(100) here because then the numbers
will only range from 0 to 99.
*/
int RandomG = num.nextInt(100)+1;
number[d] = RandomG;
System.out.print(" " +RandomG);
}
//Display the sorted numbers
System.out.print("\nSorted Numbers:"+Arrays.toString(BubbleSortAsceMethod(number)));
}
public static int [] BubbleSortAsceMethod(int[] number){
int placeholder;
for(int i = 0 ; i < number.length-1 ; i++){
for ( int x = 1 ; x < number.length-i ; x++){
/*If the first number in the sequence is greater than the second
number, than save the first number of sequence in placeholder
and place the second number in the first numbers position, and
put the placeholder in the second numbers position (SWAP).
*/
/*
Since this is saying that when the first term is bigger than the
2nd term, the sequence will increase. If we flip the relational
operator, the sequence will decrease.
*/
if ( number[x-1] < number[x]){
placeholder = number[x-1];
number[x-1] = number[x];
number[x] = placeholder;
}
}
}
return number;
}
I'm kinda new to all this java stuff so please go a bit easy on me! Any help at all is appreciated :)
As the data contained in the file will consist of a pair of values: The name (String) and the age (int), you will need to retain their relationship. The best way of doing this would be to create a Class to represent the data. Eventually you want to sort the data on age using your BubbleSort method. While practically this would not be your first choice to sort data, I assume that this is a requirement. The BubbleSort method you have sorts an int[] by comparing each entry against it's immediate neighbor. With int being primitive, you can directly compare each element using the < operator.
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.age = age;
this.name = name;
}
public String getName() { return name; }
public int getAge() { return age; }
#Override
public String toString() {
return name + System.lineSeperator() + age;
}
#Override
public int compareTo(Person person) {
return this.age - person.age;
}
}
You may want to implement the Comparable interface to compare Objects; in which the interface must be implemented by Overriding the compareTo(Person person) method. You can impose sorting on age by returning the difference in age. This is not the only way you can impose the order you want; you may wish to compare directly using the getAge() of each Object or create a Comparator object.
Using the Comparable interface does allow you to make your BubbleSort class more generic, however (though the array must be of Objects that implement the interface; hence no primitive types).
public class BubbleSort {
public static <T extends Comparable> T[] BubbleSortAsceMethod(T[] array) {
for (int i = 0; i < array.length - 1; i++) {
for (int x = 1; x < array.length - i; x++) {
if (comparator.compare(array[x - 1], array[x]) < 0) {
T placeholder = array[x - 1];
array[x - 1] = array[x];
array[x] = placeholder;
}
}
}
return array;
}
}
You will notice that this sort method has some slight differences from your original, namely the BubbleSortAsceMethod method signature with the introduction of generic type parameters. Once again, this is completely optional, though this does give you the flexibility to use this method in the future for other arrays of Classes that extend the Comparable interface.
If you don't want to use generics or the Comparable interface, you will need to change the method signature and if statement.
You're method signature should instead look like public static Person[] BubbleSortAsceMethod(Person[] array) and the if statement if (array[x-1].getAge() < array[x].getAge())
This can give you an illustration of it working, though this does not consider the file io which should be simple to implement from what you have done already.
static Random random = new Random();
public static void main (String args[]) {
int size = 100;
Person[] peopleArray = new Person[size];
for (int i = 0; i < size; i++) {
String name = generateName(random.nextInt(4) + 4);
int age = random.nextInt(100);
peopleArray[i] = new Person(name, age);
}
peopleArray = BubbleSort.BubbleSortAsceMethod(peopleArray);
}
Note that this conforms, at least as much as possible, to the code you have implemented this far. If the BubbleSort and use of arrays are not critical, data structures that implement the List interface, such as ArrayList, can allow you to implement this much cleaner. This does not use the BubbleSort method at all.
public static void main (String args[]) {
int size = 100;
ArrayList<Person> people = new ArrayList<>();
for (int i = 0; i < size; i++) {
String name = generateName(random.nextInt(4) + 4);
int age = random.nextInt(100);
people.add(new Person(name, age));
}
peopleList.sort(Person::compareTo);
//or, if you don't want to implement comparable
peopleList.sort(Comparator.comparing(Person::getAge));
}
Appendix:
Used for illustrative purposes: Generates a name of a set length (randomly).
static char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
public static String generateName(int length) {
if (length > 0) {
return alphabet[random.nextInt(alphabet.length)] + generateName(length - 1);
}
return "";
}
I have to pass the values that are in my Guitar constructor and then pass them to the generateSong method. There is one catch. The generate song method can not take parameters in because since the values are in the same class, they should be able to be able to take in the values from the constructor.
When I try to implement the values in that method, the values are not able to be accessed. How can I fix this?
public Guitar(int chord, int numOfStrings) {
//pass these values to the generateSong method
System.out.println("Guitar () generated a guitar with: " + numOfStrings + "." + "Song length is " +chord);
// declare the array for which the song is stored
// store the values of the last row i (highest index of the array)
double[] max = null;
Guitar.generateSong();
// start the generate song method
public static void generateSong () {
double [] [] song = new double [numOfStrings] [chord];
double[] max;
int findmax =0;
int sum =0;
for (int i =0; i<song.length; i++) {
for (int j =0; j<song.length; j++ ) {
sum = (int) (sum +song[i][j]);
}
for (int e=0; e<song.length; e++) {
if (song[e]!=song[findmax] ) {
max[e] =e;
}
for(int k=0; k<song.length; k++) {
for (int l=0; k<song[k].length; k++)
// assign note values to the array
song [k] [l] = 27.5 + (Math.random()* 4186);
// print out the proper value
System.out.printf("8.2%f", song);
for( int m=0; m<max.length; m++)
max[m]= 1 +( Math.random() *3);
System.out.printf("8.2%f", max);
}
}
}
}
The values int chord and int numOfStrings come from command line parameters in the main method and are passed to this method through the following object:
Guitar guitar = new Guitar (numOfStrings, chord);
So, there are two syntax errors and one misunderstanding of the requirement. Let's start with the misunderstanding.
The generate song method can not take parameters in because since the values are in the same class, they should be able to be able to take in the values from the constructor.
This is only accomplishable via fields. You need to set your constructor up so that fields for those values are created, which can then be used everywhere else in this class.
In this scenario...
public class Guitar {
private int chord;
private int numberOfStrings;
public Guitar(final int chord, final int numberOfStrings) {
this.chord = chord;
this.numberOfStrings = numberOfStrings;
}
}
Second, you can't define methods inside of other methods. Move the definition of your generateSong method out of the constructor.
Third, don't make the generateSong method static! You create an instance of these to use, and you use that instance inside of main to perform the behavior you want.
// in main()
Guitar guitar = new Guitar(4, 10);
guitar.generateSong();
As an addendum, you need to be sure that you parse the integers you get from the command line, as those values are always going to be coming in as String. I leave this as an exercise for the reader.
I am very new to Java. My current program loops through a block that asks for users input in the console until the value they type equals done. I want to store each value the user types in an array that is a class property. When I try to append this array, I get an error that says Error:(59, 18) java: not a statement. My code is below. I will point out the line that the error occurs on inside the code. Thanks for your time!
package com.example.java;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Welcome to the musical key calculator!");
System.out.println("Enter your notes one at a time.");
System.out.println("Use uppercase letters A-G and # for sharp and b for flat.(Ex. Eb)");
System.out.println("Remember that E# and B# do not exist in music!");
System.out.println("When you have entered all of your notes, type 'done'");
System.out.println("------------------------------------------------------------------");
boolean finished = false;
Scale YourScale = new Scale();
while(finished == false) {
System.out.print("Enter a note: ");
String note = scanner.nextLine();
if (note == "done'") {
finished = true;
} else {
YourScale.addNote(note);
}
}
if(finished == true){
StringBuilder output = new StringBuilder("Your notes are ");
String[] completedNotes = YourScale.notes;
for (int i = 0; i < completedNotes.length; i++) {
output.append(completedNotes[i] + " ");
}
}
}
public static class Scale {
public String[] notes = {};
public void addNote(String note){
notes[] = note; //Error occurs here.
}
}
}
Java arrays are fixed length, and that isn't how you create (or populate an array). I would prefer to use a Collection like,
public List<String> notes = new ArrayList<>();
public void addNote(String note){
notes.add(note);
}
But, you could use Arrays.copyOf(T[], int) and something like
public String[] notes = new String[0];
public void addNote(String note){
int len = notes.length;
notes = Arrays.copyOf(notes, len + 1);
notes[len] = note;
}
Finally, you do not test String equality with ==
if (note == "done'") {
should be something like
if (note.equals("done")) {
notes is a String array, which means it has many String objects inside. Also you initialize it to an empty array. Arrays should have a fixed size.
//Declare a variable notes, and initialize it as an empty array?
public String[] notes = {};
public void addNote(String note)
{
//This doesn't make sense in java - it's syntax is wrong
notes[] = note;
}
If you want to use arrays this is an example:
//Declare a variable notes, and initialize it as an array of
//specific size (I used 5 as example)
public String[] notes = new String[5];
public void addNote(String note)
{
//Here you should have some short of counter that counts in which
// position of the array you will save 'note' or just run a 'for'
//loop and the first element that is not initialized can get the note
for (int i = 0; i < notes.length; i++)
if (notes[i] == null)
{
notes[i] = note;
break;
}
}
Although this method allows you to save a fixed size, which is not desirable in your case, but nevertheless it uses Array and can help you understand how to use them.
If you want to implement it properly you should use an ArrayList. An ArrayList is an array where you can add new elements and remove them. You can find plenty of documentation online of how to use them.
You are trying to assign a String to a String array. You probably intended to add it to the array.
I have a text file that contains about 80000+ words. I'm trying to check the length of these words and see if it matches a number entered without using an Array Lists.
Say that an array has these global variables:
public static int INITIAL_SIZE = 100;
public static int size;
public String[] array = new String[INITIAL_SIZE];
I'm going to create an object:
PartArray part = new PartArray();
And a field:
part.array = new String[INITIAL_SIZE];
(And then proceed to expand the array with another method by multiplying the initial size by 2 until it can contain all 80000+ words)
But I want to assign every word in the array at 0, 1, 2, ..... (80000 -1) to something of the extent;
part.array[part.size++] = "aardvark";
.....
part.array[part.size++] = "zymurgy";
so that I can print the words that have this specific length.
part.array[0];
But how would I do that? Should I create another class in java? I just don't want to put "String" in front of every word in that text file.
I am not totaly sure if I understood what you were trying to do, but from what I understand, you want to implement something similar to an ArrayList..
First let's clarify something. The code example you posted will always result in an ArrayIndexOutOfBoundsException:
part.array[part.size++] = "aardvark";
.....
part.array[part.size++] = "zymurgy";
No matter how big your array is, you'll try to access memory, which is outside of that array.
If you really do not want to use an ArrayList (or any other List), you might want to create your own class which behaves in a similar way..
public class StringList{
public static final int DEFAULT_INITIAL_SIZE = 100;
public static final float DEFAULT_SCALE_FACTOR = 2;
private String[] content;
private float scaleFactor;
private int counter = 0;
public StringList(){
this(DEFAULT_INITIAL_SIZE);
}
public StringList(int initialSize){
this(initialSize, DEFAULT_SCALE_FACTOR);
}
public StringList(int initialSize, float scaleFactor){
this.scaleFactor = scaleFactor;
content = new String[initialSize];
}
public void add(String toAdd){
//check if we ran out of space for new content..
if(counter == content.length){
//create a new array with twice the current arrays size
String[] temp = new String[(int) (content.length * scaleFactor)];
//efficiently copy content from current array to temp
System.arraycopy(content, 0, temp, 0, content.length);
content = temp;
}
content[counter++] = toAdd;
}
public String get(int index){
return content[index];
}
public int size(){
return counter;
}
}
That class should do everything you need..
Here a short example..
StringList stringList = new StringList();
stringList.add("aardvark");
// add more stuff...
stringList.add("zymurgy");
for (int i = 0; i < stringList.size(); i++) {
String someText = stringList.get(i);
// do stuff with your string...
}
I am confused with passing ARRAYLIST values from one class to another.
I used the ARRAY in these classes before. I am changed those with ARRAYLISTS.
I have 2 classes. this class has an ARRAYLIST called "locationcells". This programs get 3 random digits from another class and get uses inputs and check if their inputs match the 3 digits. it's more like a guessing game.
import java.util.ArrayList;
class SimpleDotCom {
private ArrayList<String> locationcells;
public void setLocationcells(ArrayList<String> Locs)
{
locationcells = Locs;
}
public String CheckYourself(String StringGuess)
{
String result = " Miss";
int index = locationcells.indexOf(StringGuess);
if (index >= 0)
{
locationcells.remove(index);
if (locationcells.isEmpty())
{
result = "Kill";
}
else
{
result = "Hit";
}
}
return result;
}
}
this looks right.
Now the class with the main method:
import java.util.ArrayList;
class SimpleDotComGame {
public static void main(String[] args)
{
int numOfGuesses = 0;
GameHelper helper = new GameHelper();
SimpleDotCom theDotCom = new SimpleDotCom();
/*
this is the part I don't understand. I used to have the int array and generated random numbers and it worked well.
int randomNum = (int) (Math.random() * 5);
ArrayList<String> locations = new ArrayList<String>();
*/
theDotCom.setLocationcells(locations);
boolean isAlive = true;
while (isAlive == true)
{
String guess = helper.getUserInput("Enter a number");
String result = theDotCom.CheckYourself(guess);
numOfGuesses++;
if (result.equals("Kill"))
{
isAlive = false;
System.out.println("You took " + numOfGuesses + "guesses");
}
}
}
}
If you see the comments section above. That's the part I am getting confused. I used to have an array there. INT array. So I was able to pass the INT random numbers to the "simpledotcom" class. Now it is an arraylist with string type, I am not sure how to move forward.
Thank you all in advance,
int numericGuess = Integer.parseInt(helper.getUserInput("Enter a number"));
Also you can use a list of Integers too:
ArrayList<Integer> locations = new ArrayList<Integer>();
while(//condition){
int randomNum = (int) (Math.random() * 5);
locations.add(randomNum)
}
this way you can perform
locations.indexOf(numericGuess) or locations.contains(numericGuess)
OR
Conversely you can do,
String guess = helper.getUserInput("Enter a number");
ArrayList<String> locations = new ArrayList<String>();
while(//condition){
int randomNum = (int) (Math.random() * 5);
locations.add(String.valueOf(randomNum))
}
and check by
locations.indexOf(guess) or locations.contains(guess)
You can always transform the random int to a string by using Integer.toString() before inserting into your array list.
You can convert the String back to int using Integer.parseInt()
E.g.
for (int i = 0 ; i < 3 ; i++)
{
locations.add(Integer.toString((int)(Math.random() * 5));
}
If I understand well: add 3 Strings to the ArrayList:
ArrayList<String> locations = new ArrayList<String>();
for (i=0; i<3; i++)
{ locations.add(String.valueOf((int) (Math.random() * 5))); }
Anyway, you might refactor a little as well, starting with the extracting the above lines from the main method.
Another way might be to store your integer in a list, and convert the guesses to integers. Looks more logic to me anyway. In that case, you'll have an ArrayList. To convert a string to an integer:
int guessNumber = Integer.parseInt(guess);
or
Integer guessNumber = Integer.valueOf(guess);
Both will throw a NumberFormatException if 'guess' does not contain a parseble integer (see javadoc )
Why are you not using arrays like (apparently) you did before, by the way?