I am trying to read from a file, then print the even elements first, followed by the odd lines. Is it best to read the lines and store them in a list for even and another for odd then print each? Or is there a more efficient way around this?
the snippet of code below, is the method in which i am doing this sorting... As of now, it simply stores the input into a list and prints them. Is there an efficient way to print even lined words followed by odd numbered lines?
public static void test(BufferedReader r, PrintWriter w) throws IOException {
ArrayList<String> s = new ArrayList<String>();
String line;
int n = 0;
while ((line = r.readLine()) != null) {
s.add(line);
n++;
}
Iterator<String> i = s.iterator();
while (i.hasNext()) {
w.println(i.next());
}
}
thanks in advance for any help/input!
Well, your best bet is to print the even lines as you read them, and store the odd lines for later printing.
ArrayList<String> s = new ArrayList<String>();
String line;
int n = 0;
while ((line = r.readLine()) != null) {
if(n % 2 == 0){
s.add(line);
}
else{
w.println(line);
}
n++;
}
Iterator<String> i = s.iterator();
while (i.hasNext()) {
w.println(i.next());
}
That will half the amount of space required. Another option might be to print the odd lines to a string, then print that value to the output stream - might be more efficient for shorter inputs
You can change your loop as follows:
while (i.hasNext()) {
String odd = i.next();
if (i.hasNext()) {
String even = i.next();
w.println(even);
w.println(odd);
} else {
w.println(odd);
}
}
For small files what you're doing is fine - just iterate over your list twice printing alternate lines, evens on the first pass, odds on the second.
For large files, read the file twice and print alternate lines as before. What's a large file? That's system dependent.
Related
This is a project from school, but i'm only asking for help in the logic on one small part of it. I got most of it figured out.
I'm being given a file with lines of string integers, for example:
1234 123
12 153 23
1234
I am to read each line, compute the sum, and then go to the next one to produce this:
1357
188
1234
I'm stuck on the scanner part.
public static void doTheThing(Scanner input) {
int[] result = new int[MAX_DIGITS];
while(input.hasNextLine()) {
String line = input.nextLine();
Scanner linesc = new Scanner(line);
while(linesc.hasNext()) {
String currentLine = linesc.next();
int[] currentArray = convertArray(stringToArray(currentLine));
result = addInt(result, currentArray);
}
result = new int[MAX_DIGITS];
}
}
In a nutshell, I want to grab each big integer, put it an array of numbers, add them, and then i'll do the rest later.
What this is doing it's basically reading all the lines and adding everything and putting it into a single array.
What i'm stuck on is how do I read each line, add, reset the value to 0, and then read the next line? I've been at this for hours and i'm mind stumped.
Edit 01: I realize now that I should be using another scanner to read each line, but now i'm getting an error that looks like an infinite loop?
Edit 02: Ok, so after more hints and advice, I'm past that error, but now it's doing exactly what the original problem is.
Final Edit: Heh....fixed it. I was forgetting to reset the value to "0" before printing each value. So it makes sense that it was adding all of the values.
Yay....coding is fun....
hasNext method of the Scanner class can be used to check if there is any data available in stream or not. Accordingly, next method used to retrieve next continuous sequence of characters without white space characters. Here use of the hasNext method as condition of if doesn't make any sense as what you want is to check if the there are any numerical data left in the current line. You can use next(String pattern).
In addition, you can try this solution even though it is not optimal solution...
// In a loop
String line = input.nextLine(); //return entire line & descard newline character.
String naw[] = line.split(" "); //split line into sub strings.
/*naw contains numbers of the current line in form of string array.
Now you can perfom your logic after converting string to int.*/
I would also like to mention that it can easily & efficiently be done using java-8 streams.
An easier approach would be to abandon the Scanner altogether, let java.nio.io.Files to the reading for you and then just handle each line:
Files.lines(Paths.get("/path/to/my/file.txt"))
.map(s -> Arrays.stream(s.split("\\s+")).mapToInt(Integer::parseInt).sum())
.forEach(System.out::println);
If i were you i would be using the BufferedReader insted of the Scanner like this:
BufferedReader br = new BufferedReader(new FileReader("path"));
String line = "";
while((line = br.readLine()) != null)
{
int sum = 0;
String[] arr = line.split(" ");
for(String num : arr)
{
sum += Integer.parseInt(num);
}
System.out.println(sum);
}
Considering the level you're on, I think you should consider this solution. By using only the scanner, you can split the lines into an array of tokens, then iterate and sum the tokens by parsing them and validating that they're not empty.
import java.util.*;
class SumLines {
public static void main(String[] args) {
Scanner S = new Scanner(System.in);
while(S.hasNext()) {
String[] tokens = S.nextLine().split(" ");
int sum = 0;
for(int i = 0; i < tokens.length; i++) {
if(!tokens[i].equals("")) sum += Integer.parseInt(tokens[i]);
}
System.out.println(sum);
}
}
}
I'm trying to wrap my head around a problem I have in a programming set.
We're supposed to write code that reads from a file and prints it out. I get that, I can do it.
What he wants us to do is have it print out in reverse.
the file reads:
abc
123
987
He wants:
987
123
abc
The code, as it is, is as follows:
{
FileReader n=new FileReader("F:\\Java\\Set 8\\output1.txt");
Scanner in=new Scanner(n);
int l;
while (in.hasNext())
{
l=in.nextInt();
System.out.println(l);
}
in.close();
}
}
Yes, I am using java.io.*; and Scanner.
What would be the simplest way to do this?
EDIT EDIT EDIT
Here's the improved code, where I try to put it into an array.
The data in the array isn't printing out.
public static void main(String[] args) throws IOException
{
int[]Num=new int[20];
Scanner in=new Scanner(new FileReader("F:\\Java\\Set 8\\output1.txt"));
int k;
for (k=0;k<20;k++)
{
Num[k]=in.nextInt();
}
//in.close();
for (k=20;k<20;k--)
{
System.out.print(+Num[k]);
}
//in.close();
}
The most simplest way is to construct a List and add each line to the list while reading from the file. Once done, print the list items in reverse.
Here is my version of code for your problem.
public static void main(String[] args) throws FileNotFoundException {
FileReader n = new FileReader("/Users/sharish/Data/abc.xml");
Scanner in = new Scanner(n);
ArrayList<String> lines = new ArrayList<String>();
while (in.hasNext()) {
lines.add(in.nextLine());
}
in.close();
for (int i = lines.size() - 1; i >= 0; i--) {
System.out.println(lines.get(i));
}
}
Use Stack.
public static void displayReverse() throws FileNotFoundException {
FileReader n=new FileReader("C:\\Users\\User\\Documents\\file.txt");
Scanner in=new Scanner(n);
Stack<String> st = new Stack<String>();
while (in.hasNext()) {
st.push(in.nextLine());
}
in.close();
while(!st.isEmpty()) {
System.out.println(st.pop());
}
}
If you are permitted the use of third party APIs, Apache Commons IO contains a class, ReversedLinesFileReader, that reads files similar to a BufferedReader (except last line first). Here is the API documentation: http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/ReversedLinesFileReader.html
Another (less efficient) solution is hinted at in the comments. You can read your entire file into an ArrayList, reverse that list (e.g. by pushing its contents onto a stack and then popping it off), and then iterate through your reversed list to print.
EDIT:
Here is a crude example:
ArrayList<String> lines = new ArrayList<String>();
Scanner in = new Scanner(new FileReader("input.txt"));
while (in.hasNextLine())
{
lines.add(in.nextLine());
}
Use an ArrayList instead of a static array. We don't necessarily know the length of the file in advance so a static array doesn't make sense here. http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
Your example input 123, abc, etc, contains characters as well as ints, so your calls to hasNextInt and nextInt will eventually throw an Exception. To read lines use hasNextLine and nextLine instead. These methods return String and so our ArrayList also needs to store String. http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNextLine()
Once the file is in a list (not a good solution if the file is large - we've read the entire file into memory) we can either reverse the list (if keeping a reversed form around makes sense), or just iterate through it backwards.
for (int i=lines.size()-1; i>=0; i--) // from n-1 downTo 0
{
String line = lines.get(i);
System.out.println( line );
}
public static void main(String[] args) throws Exception{
String fileName = "F:\\Java\\Set 8\\output1.txt";
RandomAccessFile raf = new RandomAccessFile(fileName,"r");
int len = (int) raf.length();
raf.seek(len);
while(len >= 0){
if(len == 0){
raf.seek(0);
System.out.println(raf.readLine());
break;
}
raf.seek(len--);
char ch = (char)raf.read();
if(ch == '\n'){
String str = raf.readLine();
System.out.println(str);
}
}
}
try using org.apache.commons.io.input.ReversedLinesFileReader, it should do what you want.
You could read the lines like you are already doing, but instead of printing them (because that would print them in order and you need it the other way around), add them to some memory structure like a List or a Stack, and then, in a second loop, iterate this structure to print the lines in the needed order.
Using your code and the answers in the comments, here's an example of how you would store the strings into the arraylist and then print them out in reverse (building off of your own code)
{
FileReader n=new FileReader("F:\\Java\\Set 8\\output1.txt");
Scanner in=new Scanner(n);
int l;
ArrayList<String> reversed = new ArrayList<String>(); // creating a new String arraylist
while (in.hasNext())
{
l=in.nextInt();
System.out.println(l);
reversed.add(l); // storing the strings into the reversed arraylist
}
in.close();
// for loop to print out the arraylist in reversed order
for (int i = reversed.size() - 1; i >= 0; i--) {
System.out.println(reversed.get(i));
}
}
}
Using Java 8:
try(PrintWriter out =
new PrintWriter(Files.newBufferedWriter(Paths.get("out.txt")))) {
Files.lines(Paths.get("in.txt"))
.collect(Collectors.toCollection(LinkedList::new))
.descendingIterator()
.forEachRemaining(out::println);
}
public String compWord() throws IOException, ClassNotFoundException
{
// Local constants
final int MAX_COUNT = 8;
// Local variables
BufferedReader reader = new BufferedReader(new FileReader("dictionary.txt")); // Create a new BufferedReader, looking for dictionary.txt
List<String> lines = new ArrayList<String>(); // New ArrayList to keep track of the lines
String line; // Current line
Random rand = new Random(); // New random object
String word; // The computer's word
/********************* Start compWord *********************/
// Start reading the txt file
line = reader.readLine();
// WHILE the line isn't null
while(line != null)
{
// Add the line to lines list
lines.add(line);
// Go to the next line
line = reader.readLine();
}
// Set the computers word to a random word in the list
word = lines.get(rand.nextInt(lines.size()));
if(word.length() > MAX_COUNT)
compWord();
// Return the computer's word
return word;
}
From what I understand it should only be returning words less than 8 characters? Any idea what I am doing wrong? The if statement should recall compWord until the word is less than 8 characters. But for some reason I'm still get words from 10-15 chars.
Look at this code:
if(word.length() > MAX_COUNT)
compWord();
return word;
If the word that is picked is longer than your limit, you're calling compWord recursively - but ignoring the return value, and just returning the "too long" word anyway.
Personally I would suggest that you avoid the recursion, and instead just use a do/while loop:
String word;
do
{
word = lines.get(rand.nextInt(lines.size());
} while (word.length() > MAX_COUNT);
return word;
Alternatively, filter earlier while you read the lines:
while(line != null) {
if (line.length <= MAX_COUNT) {
lines.add(line);
}
line = reader.readLine();
}
return lines.get(rand.nextInt(lines.size()));
That way you're only picking out of the valid lines to start with.
Note that using Files.readAllLines is a rather simpler way of reading all the lines from a text file, by the way - and currently you're not closing the file afterwards...
If the word is longer than 8 characters, you simply call your method again, continue, and nothing changes.
So:
You are getting all the words from the file,
Then getting a random word from the List, and putting it in the word String,
And if the word is is longer than 8 characters, the method runs again.
But, at the end, it will always return the word it picked first. The problem is that you just call the method recursively, and you do nothing with the return value. You are calling a method, and it will do something, and the caller method will continue, and in this case return your word. It does not matter if this method is recursive or not.
Instead, I would recommend you use a non-recursive solution, as Skeet recommended, or learn a bit about recursion and how to use it.
I'm trying to write a program that takes in a text file as input, adds words in it as keys and the associated to the words values schould be page numbers they are located in. Text looks like this:
Page1
blah bla bl
Page2
some blah
So for word "blah" output must be
blah : [1,2].
I only inserted the keys, but I can't figure out how to insert associated values to them. Here's what I have so far:
BufferedReader reader = new BufferedReader(input);
try {
Map <String, List<Integer>> library
= new TreeMap<String, List<Integer>>();
String line = reader.readLine();
while (line != null) {
String[] tokens = line.trim().split("\\s+");
for (int i = 0; i < tokens.length; i++) {
String word = tokens[i];
if (!library.containsKey(word)
&& !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
List<Integer> pages = library.get(word);
int page = getNum(tokens[0]);
pages.add(page);
page++;
}
}
}
}
line = reader.readLine();
}
}
To get number of page I use this method
private static int getNum(String s) {
int result = 0;
int p = 1;
int i = s.length() - 1;
while (i >= 0) {
int d = s.charAt(i) - '0';
if (d >= 0 && d <= 9) {
result += d * p;
} else {
break;
}
i--;
p *= 10;
}
return result;
}
Thank's for all Your ideas!
The pages variable is declared inside the scope of your inner if statement. Once that block ends the variable is out of scope and undefined. If you want to use the list of pages later then it needs to be declared as a class variable.
I assume you are using pages to later generate a table of contents. But it's not strictly necessary as you can generate it later from your word index - I'll demonstrate how to do that below.
You also need to declare a currentPage variable which hold the latest 'PageN' text you have seen. There's no need to increment this manually: you should just store the number in the text (which copes with blank pages).
Page numbers seem to always be on their own line so page detection should be on the line text not on the word (which copes with situations where a line reads 'for more information see Page72').
It's also worth checking that there's a valid page number before your first word.
So putting that all together your code should be structured something like the following:
Map<String, Set<Integer>> index = new TreeMap<>();
int currentPage = -1;
String currentLine;
while ((currentLine = reader.readLine()) != null) {
if (isPage(currentLine)) {
currentPage = getPageNum(currentLine);
} else {
assert currentPage > 0;
for (String word: words(currentLine)) {
if (!index.contains(word))
index.put(word, new TreeSet<>());
index.get(word).add(currentPage);
}
}
}
I've separated methods words, isPage and getPageNum but you seem to have working code for all of those.
I've also changed the List of pages to a Set to reflect the fact that you only want a word-page reference once in the index.
To get an ordered list of all pages from the index use:
index.values().stream()
.flatMap(List::stream).distinct().sorted()
.collect(Collectors.toList());
That's assuming Java8 but it's not too hard to convert if you don't have streams.
If you are going to generate a reverse index (pages to words) then for efficiency reasons you should probably create the reverse map (Map<Integer, List<String>>) as you are processing the words.
You should try something like this. I'm not totally sure how you're using the pages, but this code will check if library contains the word (like you already have) and then if it doesn't it will add the page number to the list for that word.
if (!library.containsKey(word) && !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
}
else {
library.put(word, library.get(word).add(page));
}
Your problem seems to be in this piece of logic:
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
clearly you are adding page numbers only when line starts with Page otherwise the logic inside if condition is not executed so you never updated the page number for any words.
This is my code. It produces the error java.util.NoSuchElementException.
It is meant to search a file, example.txt for a word (eg. and) and find all instances of the the word and print the word either side of it also (eg. cheese and ham, tom and jerry) in ONE JOptionPane. Code:
import java.io.File;
import java.util.Arrays;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class openFileSearchWord {
public static void main(String Args[])
{
int i=0,j=0;
String searchWord = JOptionPane.showInputDialog("What Word Do You Want To Search For?");
File file = new File("example.txt");
try
{
Scanner fileScanner = new Scanner(file);
String[] array = new String[5];
String[] input = new String[1000];
while (fileScanner.hasNextLine())
{
for(i=0;i<1000;i++)
{
input[i] = fileScanner.next();
if(input[i].equalsIgnoreCase(searchWord))
{
array[j] = input[i-1] + input[i] + input[i+1];
j++;
}
}
}
Arrays.toString(array);
JOptionPane.showMessageDialog(null, array);
fileScanner.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
It looks like you're assuming each line will have 1000 words.
while (fileScanner.hasNextLine())
{
for(i=0;i<1000;i++) <-------- Hardcoded limit?
{
....
}
}
You can try putting another catch loop, or check hasNext() during that for loop.
while (fileScanner.hasNextLine())
{
for(i=0;i<1000 && fileScanner.hasNext();i++)
{
....
}
}
There are also many issues with your code, like if input[i-1] hits the -1 index, or if your 'array' array hits the limit.
I took the liberty to have some fun.
Scanner fileScanner = new Scanner(file);
List<String> array = new ArrayList<String>();
String previous, current, next;
while (fileScanner.hasNext())
{
next = fileScanner.next()); // Get the next word
if(current.equalsIgnoreCase(searchWord))
{
array.add( previous + current + next );
}
// Shift stuff
previous = current;
current = next;
next = "";
}
fileScanner.close();
// Edge case check - if the last word was the keyword
if(current.equalsIgnoreCase(searchWord))
{
array.add( previous + current );
}
// Do whatever with array
....
I see a few error here ...
You are creating two arrays one with 5 and one with 1000 elements.
In your code you are referencing elements directly by index ... but this index might not be present.
input[i-1] ... what if i = 0? ...index is -1
array[j] ... what if j > 4 ... index 5 doesn't exist
I suggest using List of elements instead of fixed arrays.
List<String> array = new ArrayList<>();
You are assuming that the input is something but don't do anything to check what it actually is.
Just as Drejc told you, The first iteration would fail because of the negative index and the program will fail as well if it finds more than 5 matches of the desired word.
Also I want to add another one. You should think that when you do this line:
array[j] = input[i-1] + input[i] + input[i+1];
You have not assigned input[i+1] yet. In that iteration you've just assigned input[i], but no the next one.
You should process the concatenation of the three elements (previousWord + match + nextWord) when reaching nextWord.
Another solution, but inefficient, would be copying all the words to an Array at beginning and using your actual code without modifying. This would work, but you would go twice through all the words.