Trouble with passing a value into loop - java

The code below runs perfectly fine if the text file consists of lines of numbers but once it gets to for example a line that says "I am 40" it skips it instead of putting 40 into the array.
Scanner inFile = null;
File file = null;
String filePath = (JOptionPane.showInputDialog("Please enter a file path"));
int size = 0;
int[] result = new int[10];
try {
file = new File(filePath);
inFile = new Scanner(file);
int skippedCounter = 0;
for(int i = 0; inFile.hasNext(); i++){
if(inFile.hasNextInt())
result[i] = inFile.nextInt();
else{
String strOut = "";
String data = inFile.next();
for(int j = 0; j <= data.length() - 1; j++){
if(!Character.isLetter(data.charAt(j))){
strOut += data.charAt(j);
}
else
skippedCounter++;
}
result[i] = Integer.parseInt(strOut);
}
}
}

next() will give you the next token not the next Line. so variable i may go past ten. you would realize this if you didnt have an empty catch : that your array is going out of bounds
solution:
don't use a result array, use a result list, and append to its end whenever you have another result
note:
another hidden exception that could be occurring is when your parseInt fails due to non-numeric data. So don't wrap everything in a giant try/catch, it just makes it harder to debug!

I suggest you to use nextInt function just one time to keep the requested value, then use that variable whenever you need it. I think nextInt function moves to the next int each time you appeal it.

The following
result[i] = Integer.parseInt(strOut)
will result in a NumberFormatException when trying to process any letter. As strOut results in an empty String ""
You'll have to check for an empty String before attempting to parse
if (!strOut.isEmpty()) {
result[i] = Integer.parseInt(strOut);
}

Related

String Index out of range: 1

Scanner user_input = new Scanner( System.in );
String cipher_input = user_input.nextLine();
String[] arr_cipher_input = cipher_input.split("");
int[] arr_ctext = new int[cipher_input.length()];
for (int i = 0; i < cipher_input.length(); i++) {
arr_ctext[i] = (int) arr_cipher_input[i].charAt(i);
}
The above code takes an input and splits it into an array (e.g. "hello" becomes ["h","e","l","l","o"]) and then I attempt to convert the characters to their ascii values which is where it returns the error in the title. It correctly converts the first character every time and then stops on the second and I can't seem to figure out why. The array lengths seem to be the same so I'm not sure what I'm doing wrong. I'd appreciate any help. Thanks in advance!
You are creating a number of one character String(s). But you are trying to access subsequent characters. There aren't any. Change charAt(i) to charAt(0) to fix. Like,
arr_ctext[i] = (int) arr_cipher_input[i].charAt(0);
or (more efficiently) skip the split and access the characters in the input directly. Like,
String cipher_input = user_input.nextLine();
int[] arr_ctext = new int[cipher_input.length()];
for (int i = 0; i < cipher_input.length(); i++) {
arr_ctext[i] = (int) cipher_input.charAt(i);
}

Using String Array and Printfile Output getting NullPointerException?

So, I'm writing a program in which I need to have a loop that "reads and writes the first character of the strings stored in each element of the array to the output file".
I keep getting a NullPointerException at: a = planets[i].charAt(0);
String[] planets = new String[8];
char a = 'a';
String pl = "planets.txt";
File file = new File(pl);
Scanner inputFile = new Scanner(file);
for(int i = 0; i < planets.length; i++){
while(inputFile.hasNext()){
planets[i] = inputFile.nextLine();
}
}
inputFile.close();
System.out.println("closed.");
String b = "planetfirst.txt";
PrintWriter outputFile = new PrintWriter(b);
for (int i = 0; i< planets.length; i++){
a = planets[i].charAt(0);
outputFile.println(a);
}
outputFile.close();
System.out.println("Data written to the file.");
Thanks in advance!
edit:
I added the rest of my program for some context :)
Your while loop is inside your for loop, so all the text will be inside planets[0], and the rest of the indices will be empty (i.e null). When you later iterate through the array with
for(int i = 0; i < planets.length; i++) {
a = planets[i].charAt(0);
}
you will get a NullPointerException when i is larger than 0.
If your textfile has 8 lines, then there is no need for the while-loop, because you have a for loop that iterates 8 times, and an array of length 8.
If the number of lines in your textfile varies, however, you shouldn't use an array, and instead use an arraylist, and instead of a for loop, only have your while loop.
Something like
List<String> planets = new ArrayList<String>();
while(inputFile.hasNext()){
planets.add(inputFile.nextLine());
}

I keep getting this error while attempting to scramble a .wav file in Java: java.lang.NumberFormatException.forInputString(Unknown Source)

My code compiles, but when I try to use the method to scramble the .wav file I get an error
Here is the code that is causing the problem:
public Sound scrambleSound(){
SoundSample[] sampleArray = this.getSamples();
ArrayList<Integer> sounds = new ArrayList<Integer>(0);
String origin = "";
for(SoundSample s : sampleArray){
origin = "" + s.getValue();
for(int i = 0; i<origin.length();i++){
int n = Integer.parseInt(origin.substring(i,i+1)); //the error is here
if(i == origin.length() - 1){
Integer q = new Integer((int)(Math.pow(3,n))+2);
sounds.add(q);
}
else{
Integer w = new Integer((int)(Math.pow(3,n))+1);
sounds.add(w);
}
}
}
Sound sound1 = new Sound(sounds.size());
for(int z = 0; z<sounds.size(); z++){
sound1.setSampleValueAt(z, sounds.get(z).intValue());
}
return sound1;
}
You have
for(int i = 0; i<origin.length();i++){
This should be
for(int i = 0; i<origin.length()-1;i++){
because in your substring, you are looking at i+1. You might want to consider using origin.charAt(i) instead, this is the usual way to do it and you will not need to adjust your loop bounds. A substring will work fine with the modification to the loop, however. In addition, you might be trying to turn a character like the - in -1 into an integer, maybe try-catch?

Java String Array Mergesort

Hi all I wrote a mergesort program for a string array that reads in .txt files from the user. But what I want to do now is compare both files and print out the words in file one and not in file two for example apple is in file 1 but not file 2. I tried storing it in a string array again and then printing that out at the end but I just cant seem to implement it.
Here is what I have,
FileIO reader = new FileIO();
String words[] = reader.load("C:\\list1.txt");
String list[] = reader.load("C:\\list2.txt");
mergeSort(words);
mergeSort(list);
String x = null ;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length; j++)
{
if(!words[i].equals(list[j]))
{
x = words[i];
}
}
}
System.out.println(x);
Any help or suggestions would be appriciated!
If you want to check the words that are in the first array but do not exist in the second, you can do like this:
boolean notEqual = true;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length && notEqual; j++)
{
if(words[i].equals(list[j])) // If the word of file one exist
{ // file two we set notEqual to false
notEqual = false; // and we terminate the inner cycle
}
}
if(notEqual) // If the notEqual remained true
System.out.println(words[i]); // we print the the element of file one
// that do not exist in the second file
notEqual = true; // set variable to true to be used check
} // the other words of file one.
Basically, you take a word from the first file (string from the array) and check if there is a word in file two that is equal. If you find it, you set the control variable notEqual to false, thus getting out of the inner loop for and not print the word. Otherwise, if there is not any word on file two that match the word from file one, the control variable notEqual will be true. Hence, print the element outside the inner loop for.
You can replace the printing statement, for another one that store the unique word in an extra array, if you wish.
Another solution, although slower that the first one:
List <String> file1Words = Arrays.asList(words);
List <String> file2Words = Arrays.asList(list);
for(String s : file1Words)
if(!file2Words.contains(s))
System.out.println(s);
You convert your arrays to a List using the method Arrays.asList, and use the method contains to verify if the word of the first file is on the second file.
Why not just convert the Arrays to Sets? Then you can simply do
result = wordsSet.removeAll(listSet);
your result will contain all the words that do not exist in list2.txt
Also keep in mind that the set will remove duplicates ;)
you can also just go through the loop and add it when you reached list.length-1.
and if it matches you can break the whole stuff
FileIO reader = new FileIO();
String words[] = reader.load("C:\\list1.txt");
String list[] = reader.load("C:\\list2.txt");
mergeSort(words);
mergeSort(list);
//never ever null
String x = "" ;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length; j++)
{
if(words[i].equals(list[j]))
break;
if(j == list.length-1)
x += words[i] + " ";
}
}
System.out.println(x);
Here is a version (though it does not use sorting)
String[] file1 = {"word1", "word2", "word3", "word4"};
String[] file2 = {"word2", "word3"};
List<String> l1 = new ArrayList(Arrays.asList(file1));
List<String> l2 = Arrays.asList(file2);
l1.removeAll(l2);
System.out.println("Not in file2 " + l1);
it prints
Not in file2 [word1, word4]
This looks kind of close. What you're doing is for every string in words, you're comparing it to every word in list, so if you have even one string in list that's not in words, x is getting set.
What I'd suggest is changing if(!words[i].equals(list[j])) to if(words[i].equals(list[j])). So now you know that the string in words appears in list, so you don't need to display it. if you completely cycle through list without seeing the word, then you know you need to explain it. So something like this:
for(int i = 0; i<words.length; i++)
{
boolean wordFoundInList = false;
for(int j = 0; j<list.length; j++)
{
if(words[i].equals(list[j]))
{
wordFoundInList = true;
break;
}
}
if (!wordFoundInList) {
System.out.println(x);
}
}

Optimizing Project Euler #22

Thanks in advance.
I just solved Project Euler #22, a problem involving reading about 5,000 lines of text out of a file and determining the value of a specific name, based on the sum of that Strings characters, and its position alphabetically.
However, the code takes about 5-10 seconds to run, which is a bit annoying. What is the best way to optimize this code? I'm currently using a Scanner to read the file into a String. Is there another, more efficient way to do this? (I tried using a BufferedReader, but that was even slower)
public static int P22(){
String s = null;
try{
//create a new Scanner to read file
Scanner in = new Scanner(new File("names.txt"));
while(in.hasNext()){
//add the next line to the string
s+=in.next();
}
}catch(Exception e){
}
//this just filters out the quotation marks surrounding all the names
String r = "";
for(int i = 0;i<s.length();i++){
if(s.charAt(i) != '"'){
r += s.charAt(i);
}
}
//splits the string into an array, using the commas separating each name
String text[] = r.split(",");
Arrays.sort(text);
int solution = 0;
//go through each string in the array, summing its characters
for(int i = 0;i<text.length;i++){
int sum = 0;
String name = text[i];
for(int j = 0;j<name.length();j++){
sum += (int)name.charAt(j)-64;
}
solution += sum*(i+1);
}
return solution;
}
If you're going to use Scanner, why not use it for what it's supposed to do (tokenisation)?
Scanner in = new Scanner(new File("names.txt")).useDelimiter("[\",]+");
ArrayList<String> text = new ArrayList<String>();
while (in.hasNext()) {
text.add(in.next());
}
Collections.sort(text);
You do not need to strip quotes, or split on commas - Scanner does it all for you.
This snippet, including java startup time, executes in 0.625s (user time) on my machine. I suspect it should be a bit faster than what you were doing.
EDIT OP asked what the string passed to useDelimiter was. It's a regular expression. When you strip out the escaping required by Java to include a quote character into a string, it's [",]+ - and the meaning is:
[...] character class: match any of these characters, so
[",] match a quote or a comma
...+ one or more occurence modifier, so
[",]+ match one or more of quotes or commas
Sequences that would match this pattern include:
"
,
,,,,
""",,,",","
and indeed ",", what was what we were going after here.
I suggest you to run your code with profiler. It allows you to understand, what part is really slow (IO/computations etc). If IO is slow, check for NIO: http://docs.oracle.com/javase/1.4.2/docs/guide/nio/.
Appending strings in a loop with '+', like you do here:
/* That's actually not the problem since there is only one line. */
while(in.hasNext()){
//add the next line to the string
s+=in.next();
}
is slow, because it has to create a new string and copy everything around in each iteration. Try using a StringBuilder,
StringBuilder sb = new StringBuilder();
while(in.hasNext()){
sb.append(in.next());
}
s = sb.toString();
But, you shouldn't really read the file contents into a String, you should create a String[] or an ArrayList<String> from the file contents directly,
int names = 5000; // use the correct number of lines in the file!
String[] sa = new String[names];
for(int i = 0; i < names; ++i){
sa[i] = in.next();
}
However, upon checking, it turns out that the file does not contain about 5000 lines, rather, it is all on a single line, so your big problem is actually
/* This one is the problem! */
String r = "";
for(int i = 0;i<s.length();i++){
if(s.charAt(i) != '"'){
r += s.charAt(i);
}
}
Use a StringBuilder for that. Or, make your Scanner read until the next ',' and read directly into an ArrayList<String> and just remove the double quotes from each single name in the ArrayList.
5+ seconds is quite slow for this problem. My entire web application (600 Java classes) compiles in four seconds. The root of your problem is probably the allocation of a new String for every character in the file: r += s.charAt(i)
To really speed this up, you should not use Strings at all. Get the file size, and read the whole thing into a byte array in a single I/O call:
public class Names {
private byte[] data;
private class Name implements Comparable<Name> {
private int start; // index into data
private int length;
public Name(int start, int length) { ...; }
public int compareTo(Name arg0) {
...
}
public int score()
}
public Names(File file) throws Exception {
data = new byte[(int) file.length()];
new FileInputStream(file).read(data, 0, data.length);
}
public int score() {
SortedSet<Name> names = new ...
for (int i = 0; i < data.length; ++i) {
// find limits of each name, add to the set
}
// Calculate total score...
}
}
Depending on the application, StreamTokenizer is often measurably faster than Scanner. Examples comparing the two may be found here and here.
Addendum: Euler Project 22 includes deriving a kind of checksum of the characters in each token encountered. Rather than traversing the token twice, a custom analyzer could combine the recognition and calculation. The result would be stored in a SortedMap<String, Integer> for later iteration in finding the grand total.
An obtuse solution which may find interesting.
long start = System.nanoTime();
long sum = 0;
int runs = 10000;
for (int r = 0; r < runs; r++) {
FileChannel channel = new FileInputStream("names.txt").getChannel();
ByteBuffer bb = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
TLongArrayList values = new TLongArrayList();
long wordId = 0;
int shift = 63;
while (true) {
int b = bb.remaining() < 1 ? ',' : bb.get();
if (b == ',') {
values.add(wordId);
wordId = 0;
shift = 63;
if (bb.remaining() < 1) break;
} else if (b >= 'A' && b <= 'Z') {
shift -= 5;
long n = b - 'A' + 1;
wordId = (wordId | (n << shift)) + n;
} else if (b != '"') {
throw new AssertionError("Unexpected ch '" + (char) b + "'");
}
}
values.sort();
sum = 0;
for (int i = 0; i < values.size(); i++) {
long wordSum = values.get(i) & ((1 << 8) - 1);
sum += (i + 1) * wordSum;
}
}
long time = System.nanoTime() - start;
System.out.printf("%d took %.3f ms%n", sum, time / 1e6);
prints
XXXXXXX took 27.817 ms.

Categories

Resources