Data structure usage - java

I recently faced a question where I need to display the last n lines in a file in java. It is similar to implementing tail function of unix in java but I just have readline() method and a method to check the end of file. No other methods. I was thinking of an approach with Queue data structure like this:
Read n lines starting from the first line of the file.
store the n lines read in the queue.
Check if we have reached the end of file. If yes, print the contents of the queue.
If not, read n more lines and push them in the queue.
Can anyone think of any other approach?

What about a ring buffer of size n where you override the oldest entry?
It would basically look like the code below. I made up the functions to read the file but you should get the idea.
String[] lines = new String[n];
int i = 0;
while(!file.eof()) {
String line = file.readLine();
lines[i] = line;
i = (i + 1) % n;
}
for(int j = 0; j < n; j++) {
if (lines[i] != null) {
System.out.println(lines[i]);
}
i = (i + 1) % n;
}

Related

Count no of lines between two lines

How to achieve the following. Here is a sample text file..
AH
1
2
3
BH
21
BT03
CH
CT02
AT10
This is a sample text file. I need read each line and find the count.. For example, there are 10 Lines within A record.. And 3 lines within B record and two lines within C Record.
How do I get this count. H-Header and T-Trailer. You may say, read the T record to find the count, but that count might be wrong. Hence I am trying to find the count and update the trailer records correctly.
I cannot upload the Java code I have written as I'm on mobile now.. Any suggestions is highly appreciated
Thanks
I'm not sure if I understand your question, you just want to count lines in a file? Try something like this:
Path path = Paths.get("yourFile.txt");
long lineCount = Files.lines(path).count();
use below code and read all file in array.
String[] stringArray = new String[10];
int length = stringArray.length;
for (int i = 0; i < length; i++) {
String stringI = stringArray[i];
if (stringI.contains("H")) {
// Head rec
String headRecName = stringI.replace("H", "");
int count = 1;
for (int j = i + 1; j < length; j++) {
count++;
String stringJ = stringArray[j];
if (stringJ.contains("T") && headRecName.equals(stringJ.replace("T", ""))) {
stringArray[j] = stringArray[j] + count;
}
}
}
}
}

CSV reader perils - Java

I'm trying to read a CSV file and split each line into 4 different integer values via a two-dimensional array in java.
I'm using openCSV 3.8.
For the sake of simplicity, say this is the contents of the CSV file (the full file contains 306 lines just like these):
76,67,0,1
77,65,3,1
78,65,1,2
83,58,2,2
I can read the file just fine, and I can use System.out.println to output each single value to the console, like this:
76
67
0
1
77
65
3
1
78
65
1
2
85
58
2
2
Unfortunately with my code below, designed to enter each value into a separate array element only saves the 4 values in the last line of the file.
And here is my java code (don't mind the size of the iaData array, it's sized for the full CSV file):
public static void main(String[] args) {
//String outputStr = "";
int[][] iaData = new int[306][4];
int i = 0;
int x = 0;
try
{
//Get the CSVReader instance with specifying the delimiter to be used
CSVReader reader = new CSVReader(new FileReader("haberman.data"),',');
String [] nextLine = new String[1250];
//Read one line at a time
while ((nextLine = reader.readNext()) != null)
{
for (i = 0; i <= 305; i++)
{
for (x = 0; x <= 3; x++)
{
iaData[i][x] = Integer.parseInt(nextLine[x]);
}
}
}
for (int z = 0; z <= 3; z++)
{
System.out.println(iaData[0][z] + "\n");
}
reader.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
With this code, I would expect my System.out.println(iaData[0][z] + "\n"); to output the following to the console (the values in the first line of the file):
76
67
0
1
Unfortunately it's not the case, it actually outputs the following (the 4 values in the last line of the file):
83
58
2
2
What is wrong with my code such that iaData[0][0/1/2/3] actually outputs what I would expect to be held in iaData[**3**][0/1/2/3]?
For every line, you start writing with first index i=0.
So for every line you override all information from the line before:
while ((nextLine = reader.readNext()) != null)
{
for (i = 0; i <= 305; i++)
{
for (x = 0; x <= 3; x++)
{
iaData[i][x] = Integer.parseInt(nextLine[x]);
}
}
}
This should solve your problem:
int i = 0;
while ((nextLine = reader.readNext()) != null) {
for (x = 0; x <= 3; x++) {
iaData[i][x] = Integer.parseInt(nextLine[x]);
}
i++;
}
Your current problem is that for each line you are iterating over the entire 2D array, both rowwise and columnwise. This has the effect that only the last row will reflect the currently read line.
Instead, the row counter i should only be incremented after another line has been read from the CSV file. Currently, you are incrementing i for the same line over and over again.
// Read one line at a time
int i = 0;
while ((nextLine = reader.readNext()) != null) {
for (x = 0; x <= 3; x++) {
iaData[i][x] = Integer.parseInt(nextLine[x]);
}
// increment i once, after having processed a single line from the file
++i;
}
There are various things in your code that simply don't make sense.
First, you are init'ing nextLine to probably hold 1250 lines.
String [] nextLine = new String[1250];
But then, you are pushing a single line into that:
while ((nextLine = reader.readNext()) != null)
Either you don't need the first statement; or something is wrong about the second one.
For the actual bug you are observing: it doesn't help that you keep writing the same lines 395 times, too. And that is what your code is doing; because for each line that you read, you do
for (i = 0; i <= 305; i++)
{
for (x = 0; x <= 3; x++)
{
hiaData[i][x] = Integer.parseInt(nextLine[x]);
So you keep overwriting your data, instead of
line1
line2
...
you keep writing
line i
line i...
Thus, in the end, you only got your last line in there.
My recommendation: don't do all that manual size-dependent iterating yourself. Simply use
List<String[]> allLines = csvreader.readAll();
4 values, 395 lines ... that is nothing. Just push all of that into memory with that one call.
Meaning: the library offers you a nice abstraction that requires you one line of code to read all content. You choose to write 20, 30 lines of code instead. And that is the thing: the more code you write, the higher are chances to create bugs.
And finally: do not use such numbers as 305, 4, 1205 directly in your source code. If at all, use constants there. But hard-coding those values in your loops ... very bad practice - you have to change each and any place that deals with your input when for example 5 columns come in, instead of 4.
If the program is going to read the whole file into an array ... is it not enough to read it into memory, and process it later?
Like so:
import au.com.bytecode.opencsv.CSVReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
public class Csv {
public static void main(String[] args) throws IOException {
String string = "76,67,0,1\n" +
"77,65,3,1\n" +
"78,65,1,2\n" +
"83,58,2,2";
CSVReader reader = new CSVReader(new StringReader(string),',');
List<String[]> lines = reader.readAll();
for (String[] entries : lines) {
for (String entry: entries) {
System.out.println(Integer.parseInt(entry));
}
}
}
}
Beware of memory issues and set an upper bound or process a line a time by changing the loop like so:
String[] entries;
while((entries = reader.readNext()) != null) {
for (String entry : entries) {
System.out.println(Integer.parseInt(entry));
}
}
Problems:
1.
for (i = 0; i <= 305; i++)
This cycle is not needed, as reader.readNext() will gather all the lines without the need of further help. So, this is certainly an improvement:
int i = 0;
while ((nextLine = reader.readNext()) != null)
{
//for (i = 0; i <= 305; i++)
//{
for (x = 0; x <= 3; x++)
{
iaData[i++][x] = Integer.parseInt(nextLine[x]);
}
//}
}
2.
The other problem you have is that you iterate only the elements of the first element:
for (int z = 0; z <= 3; z++)
{
System.out.println(iaData[0][z] + "\n");
}
Instead:
for (i = 0; i < iaData.length; i++)
{
for (int z = 0; z <= 3; z++)
{
System.out.println(iaData[i][z] + "\n");
}
System.out.println("");
}

Java: how to reverse the order of every N elements in an ArrayList

I have an input text file of thousands of lines of words, where I would like write to the output file, where I reverse the order of every 10 lines. I have iterated over the entire text file, and stored it in an ArrayList<String> array and I am now trying to figure out how I can reverse the order of every 10 lines in the entire ArrayList.
so for example the output should be like this: Line : 10, 9, 8, 7 ...... 1, 20, 19, 18, 17.....11, 30, 29, 28, 27.....21 and so on until I have done this for the entire text file (Stored in the ArrayList). Below is the portion of code I have been using to try and reverse the lines as stated.
for(int i = array.size()-1; i >= array.size()-10; i--){
array.add(array.get(i));
}
for (String text : array) {
w.println(text);
}
}
What I have so far, reads and reverses only the last 10 lines of the input file and writes it to the output file. I have been having trouble figuring out a way to iteratively achieve this type of pattern throughout the entire data set, making sure that I do not hit an index out of bounds error.
Use a simple streaming approach. This is basically the current solution applied every ten lines instead of once at the end.
Read ten lines in.
Reverse these lines1.
Write the ten reversed lines out.
Repeat until the entire file is processed.
The only edge case is doing something appropriate at the end when the file isn't a multiple of 10 lines.
This same streaming approach can be used to create a new each-10 reversed list. It only 'becomes complicated' when trying to mutating the original list.
1 Steps 2 and 3 can be combined by iterating the list of ten lines backward when writing to the output.
Two approaches:
If it is already in memory, in an ArrayList, simply update that list.
If not already in memory, process 10 lines at a time.
This allows infinitely large data to be processed without running out of memory.
Option 1.
List<String> list = new ArrayList<>();
// code filling list
for (int i = 0; i < list.size(); i += 10) {
int endOfBlock = Math.min(i + 10, list.size());
for (int j = i, k = endOfBlock - 1; j < k; j++, k--) {
String temp = list.get(j);
list.set(j, list.get(k));
list.set(k, temp);
}
}
Option 2.
try (BufferedReader in = new BufferedReader(new FileReader(inFile)),
PrintWriter out = new PrintWriter(new FileWriter(outFile))) {
String[] buf = new String[10];
int len = 0;
for (String line; (line = in.readLine()) != null; ) {
buf[len++] = line;
if (len == 10) {
while (len > 0)
out.println(buf[--len]);
}
}
while (len > 0)
out.println(buf[--len]);
}
Try this
for (int i = 0, size = array.size(); i < size; i += 10)
for (int from = i, to = Math.min(i + 10, size); from < to;)
Collections.swap(array, from++, --to);
Use a secondary counter variable and an if statement to check for bounds, such as:
while(counter<array.size()+10)
int counter = 9; //since index 9 is the 10th line
for(int i=counter; i>counter-10; i--){
if(i<array.size()){
array.add(array.get(i));
}
}
counter+=10;
}
for (String text : array){
w.println(text);
}
My only concern here is that you appear to just continue adding to the existing array rather than reordering it or adding the elements to a new array?

Print first 20 items in array in reverse, then print the next 20 in reverse, and so on

so I'm working on my Java assignment where I'm given a big array.
I'm told to print the first 20 items in the array in reverse order,
then print the next 20 items in reverse order again, and so forth until I reach the end of the array.
I was able to work out how to print the first items in reverse, but then I'm having trouble implementing something that would let me continue where I left from the original array.
I'm also only allowed to have 21 items stored at a time.
Here's what I have so far (50items instead of 20)
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
LinkedList<String> s = new LinkedList<String>();
int counter = 0;
int max = 50;
for (String line = r.readLine(); line != null; line = r.readLine()) {
if (counter < max) {
s.addFirst(line);
counter++;
}
if (counter == max) {
for (String n : s) {
System.out.println(n);
}
}
}
}
I was wondering if someone can help me out, not sure what I can do from here.
First, you need to print the list whenever counter hits a multiple of 20 as well as when it hits max. Then, after you print the contents of s, clear the list:
s.clear();
That will remove all elements so it will fill up again. You also need to print the list after the for loop exits, otherwise the last few items will be left unprinted.
Note that you are not using an array anywhere in this code. It's not clear that you are following the spirit of the assignment by using a LinkedList. But only you know what the rubric is.
I hope this can get you started:
void example() {
for (int i = 0; i < 50; i++) { //fill array to be read (for this example)
myArray[i] = i;
}
readback();
}
void readback() {
int batch = 1; //represents a portion of the read operation
int batchSize = 20; //the size of the read portion
int pos = 0; //the current index of the array while it is being read
int hi; //the top of the batch
int lo; //the bottom of the batch
while (pos < myArray.length) {
if (batch*batchSize<myArray.length) { //make sure you are not going over the array boundary
hi = batch*batchSize;
lo = hi - batchSize;
} else {
hi = myArray.length;
lo = pos;
}
for (int i = hi - 1; i >= lo; i--) { //read
System.out.println(myArray[i]);
pos++;
}
batch++; //go to the next batch
}
}
For this part of the question:
I'm told to print the first 20 items in the array in reverse order, then print the next 20 items in reverse order again, and so forth until I reach the end of the array.
One simple solution would be to:
iterate 20 places in the array
store this position in a temp index
iterate back 20 places printing the array
repeat process from stored temp index
Also, keep in mind if the last print might have less than 20 elements.
int size = 20; // size of reversed chunks
for(int i = 0; i < array.length; i += size) {
int j = (i + (size - 1) < array.length) ? (i + size - 1) : array.length - 1;
for(; j >= i; j--) {
System.out.print(array[j] + " ");
}
}
However, there is no array in your code so I am not sure what you meant by that. You are reading values from a file and then using a LinkedList to print them in reverse. A better, more natural data structure, for printing in reverse (as well as most "reversal" operations) would be a Stack although Java's implementation for LinkedList is implemented such that it allows for Stack (LIFO) behavior. It is just generally used as a Queue (FIFO) structure. My answer will use a LinkedList as well to make it consistent with your approach but think about a Stack in this situation in the future.
So, since you are reading numbers, line by line from a file, here is what you can do:
You can read and insert the numbers at the top of a LinkedList until you reach the max value or the end of file
You already have that part working
Print all the numbers by removing them from the top of the LinkedList which will make them in reverse order
You are printing them but not removing them or clearing the list by calling s.clear()
Once you reach the end of file you could end up with values still in the LinkedList because you reached end of file before you reached max items and the loop finished but nothing was printed. Print these values as well.
Another thing, it seems like you are not writing to the file so you don't need the PrintWriter parameter of the function.
Here is the code:
public static void doIt(BufferedReader r) throws IOException {
LinkedList<String> s = new LinkedList<String>();
int counter = 0;
int max = 50;
for (String line = r.readLine(); line != null; line = r.readLine()) {
if (counter < max) {
s.addFirst(line);
counter++;
}
if (counter == max) {
while(!s.isEmpty()) { // remove and print in reverse order
System.out.println(s.removeFirst());
}
counter = 0; // reset counter
}
}
// print the remaining elements, if they exist
while(!s.isEmpty()) { // remove and print in reverse order
System.out.println(s.removeFirst());
}
}

How to determine ASCII value of a word

I am creating a program that imports a large list of words. This list has been separated by word but I now need to determine the ASCII value of each word in this list, and eventually which one has the highest total ASCII value. I am receiving a few errors and need to know how to get this corrected so that I can get each value.
public static void main(String[] args) throws IOException {
//import list of words
BufferedReader File = new BufferedReader(new FileReader(LOC));
//Create a temporary ArrayList to store data
ArrayList<String> words = new ArrayList<String>();
//Find number of lines in txt file
String line;
String delimiter = "\t";
while ((line = File.readLine()) != null)
//read the file
{
String[] wordsInLine = line.split(delimiter);
//separate the words
for(int i=0, isize = wordsInLine.length; i < isize; i++){
words.add(wordsInLine[i]);//put them in a list
//assess each character in the word to determine the ascii value
int total = 0;
for (int i=0; i < wordsInLine.length(); i++)
Receiving an error on the above line that states - Cannot invoke length() on the array type
String[]
- Duplicate local variable i
{
char c = word.charAt(i);
Receiving an error on the above line that states word cannot be resolved
int j = (int) c;
total += c;
}
I have done some research trying to determine the best way to calculate the ASCII value of each word and I haven't been able to find much information on how to do this. If someone could please take a look at my code I would appreciate it!! Also, before anyone says it let me just say this is NOT a school project. I am on summer break and beginning programming II in the fall and just trying to keep up on coding so that I am not rusty in the fall. THANK YOU!!! :))
Receiving an error on the above line that states - Cannot invoke length() on the array type String[] - Duplicate local variable i
wordsInLine is an array, and length is property of array. So, you have to use:
wordsInLine.length
If wordsInLine was a String, then wordsInLine.length() would have made sense.
Receiving an error on the above line that states word cannot be resolved
Before the line char c = word.charAt(i);, add below:
String word = wordsInLine[i];
For the wordsInLine.length() issue, length() is not a valid method for arrays. You actually have to access the length field thusly: wordsInLine.length without ().
As for word.charAt(i), you haven't declared a variable called word anywhere which is what's causing the problem. What you really want to do is sum up the values for every word in the array, and for that you need a nested loop.
You also said that you wanted to figure out which one had the highest value. To do that, just keep track of the largest one and update it after each iteration like this:
int indexOfMax = 0;
int[] sums = new int[wordsInLine.length];
//Iterate over every word
for(int i = 0; i < wordsInLine.length; i++)
{
//Reset the total for each word
total = 0;
//Iterate over every character in the word
for(int j = 0; j < wordsInLine[i].length(); j++)
{
char c = wordsInLine[i].charAt(j);
total += c;
}
//Remember the sum for this word
sums[i] = total;
//If the word's sum is greater than our previous max,
//make it the new max
if(sums[i] > sums[indexOfMax])
{
indexOfMax = i;
}
}
And now you can get the word with the greatest ASCII value by calling wordsInLine[indexOfMax]. It will have an ASCII sum of sums[indexOfMax].
wordsInLine is an array and therefore it does not have a method to get its length. Instead, to get an array's length, use array.length as opposed to what you were doing: array.length() (which causes an error).
word is not a defined variable, this is why java is saying that it cannot be resolved (it can't find any declaration). Instead you want to use 2 for loops in order to loop over every character in the word in the array wordsInLine. You also have two instances of the variable i, this is not allowed. To fix these errors write the following code after `int total = 0;':
int total = 0; // Don't rewrite this line
int[] totals = new int[wordsInLine.length]; // If you want to add all your totals to an array
for (int j=0; j < wordsInLine.length; j++) {
total = 0;
for (int k=0; k < wordsInLine[j].length(); k++) { // Here wordsInLine[j] is a string so you use .length() instead of .length
char c = wordsInLine[j].charAt(k);
int w = (int) c; // Get ascii of c
total += w; // Add it to total
}
// Do something with the total of this word before it gets reset to 0
// Maybe add it to an array of totals:
totals[j] = total;
}
I hope this helps!
Well your organization of your code needs a little bit of work.
First I would take this whole block of code outside file read in while loop.
for (int i=0; i < wordsInLine.length(); i++)
{
char c = word.charAt(i);
int j = (int) c;
total += c;
}
Why? Lets split what you are doing into two steps. Read in all the words into the word list. After doing this you will find where your core root of the problem is. You aren't reading the words from your word list at all.
Further code cleanup
for(int i=0, isize = wordsInLine.length; i < isize; i++){
This line is a little bit bloated. You don't need isize at all you are essentially doing denoting it for no reason. (Well actually caching the length does improve efficiency, another talk for another day). Cleaning up.
for(int i=0, ; i < wordsInLine.length; i++){
Then fixing the entire project
//import list of words
BufferedReader File = new BufferedReader(new FileReader(LOC));
//Create a temporary ArrayList to store data
ArrayList<String> words = new ArrayList<String>();
//Find number of lines in txt file
String line;
String delimiter = "\t";
// adds all the words into the list.
while ((line = File.readLine()) != null)
{
String[] wordsInLine = line.split(delimiter);
for(int i=0, ; i < wordsInLine.length; i++){
// compute alg and store the value some how to the word.
words.add(wordsInLine[i])
}
}
// notice outside the while loop.
// .size() is used for lists and .length is used for arrays.
for(int i = 0; i < words.size(); i++){
// compare
}

Categories

Resources