Parallel Arrays and reading from a file - java

I need help making a parallel array I need to read in from a textfile of strings and create a array of strings that adds each name once and increments repeated strings in an array of ints..... any ideas of how i can fix this code to do that?
Scanner sc=new Scanner(new File("Cat.txt"));
String category=sc.nextLine();
int total=sc.nextInt();
int[]totcat=new int[total];
String[]names=new String[total];
while(sc.hasNextLine())
{
String x=sc.nextLine();
boolean b=false;
int size=0;
for(int i=0;i<names.length;i++)
{
if(x.equals(names[i]))
{
b=true;
totcat[i]++;
}
}
if(!b)
{
names[size]=x;
totcat[p]++;
size;
}
}

The problem is the line if(names[j].equals(null)). This will never evaluate to true, since for that to happen, names[j] would have to be null, and so it would instead throw a NullPointerException. The correct way to write it would be if(names[j] == null).
A more elegant way would be to have another variable to keep track of how many strings you have in your array, so that if you don't find a repeated string (your if(!b) block), you can just add the string at the index indicated by the size variable, instead of having to go through the whole array looking for a null space.

It sounds like you need to read a file with Strings that are delimited by line breaks, and you want to end up with a set of all Strings found in the file as well as a count of the number of times each String occurs in the file.
Rather than trying to build an array-based structure, I'd recommend using a Map. As you read each line in the source file you check the map to see if the String value already exists in the map. If so, you increment it's value (an int), if not, you add the String to the Map.
Something like this:
Map<String, Integer> map = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
if(map.containsKey(line)) {
Integer lineCount = map.get(line);
map.put(line, lineCount++);
} else {
map.put(line, 1);
}
}
} catch(IOException ioe) {
// Handle exception
}
Something to watch our for here is memory limitations. If the file you are reading is very large and/or your Java stack size is small, you may encounter OutOfMemoryExceptions.

Related

How to retrieve array values and assign to String variable in java

I am trying to store the contents from a file into an array String retval[] , copy that array to String[] fed() and pass the array into main. So far, the array stores and copies but the array method returns null in main String []feed; feed=uio.fed();.
UserIO.java
package fileio;
import classes.*;
import java.util.*;
import java.lang.*;
import java.io.*;
public class UserIO
{
public String search (String line0)
{
String line;
try
{
FileInputStream ufin = new FileInputStream("E:\\3rd sem\\OOP\\Projects\\New folder (2)\\BOOK LIBRARY\\fileio\\user.txt");
Scanner sc = new Scanner(ufin);
while (sc.hasNextLine())
{
line=sc.nextLine();
if(line.contains(line0))
{
String retval[]= line.split(" ");
feed= new String[retval.length];
for (String s: retval)
{
System.out.println("\t\t\tFrom retval:"+s);
}
for (int n=0;n<retval.length;n++)
{
feed[n]=retval[n];
System.out.println("\tFrom feed:"+feed[n]);
}
}
}
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
return line0;
}
public static String [] feed;
public static String[] fed()
{
String [] fd;
fd= new String[feed.length];
for (int n=0;n<feed.length;n++)
{
fd[n]=feed[n];
System.out.println("From fd:"+fd[n]);
}
return fd;
}
}
Down below is the main method
Execute.java
import java.lang.*;
import java.util.*;
import classes.*;
import fileio.*;
public class Execute
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String adminusername = "a";
String adminpassword = "p";
String readerusername = "r";
String readerpassword = "p";
String nreaderusername;
String nreaderpassword;
Library b = new Library();
UserFileReadWriteDemo ufrwd = new UserFileReadWriteDemo();
UserIO uio = new UserIO();
System.out.println("enter id ");
String id = sc.next();
uio.search(id);
try
{
String []feed;
feed=uio.fed();
//uio.fed()=feed.clone;
for(int s=0;s<feed.length;s+=5)
{
String nid00= null;
feed[0+s]= nid00;
String name00=null;
feed[1+s]= name00;
String age00= null;
feed[2+s]= age00;
String uname00= null;
feed[3+s]= uname00;
String upassword00= null;
feed[4+s]= upassword00;
Reader c00 = new Reader(nid00, name00, age00,uname00,upassword00);
b.insertReader(c00);
System.out.println(" In main"+feed[s]);
}
}
catch (NullPointerException n)
{
n.printStackTrace();
}
}
Your code is a little bit difficult to read and also has a lot of unnecessary repetitions, for example method fed has no role, why not call search and make search return an array with the found elements? You are making search return the line you are searching for which you already know when you gave search that argument in the first place, it is just returning a useless value.
Also it is difficult to understand what search actually does, from what i see it finds the last occurrence of line0 in the file, because it continues to iterate over lines and every time it finds line0 it will create new feed array in UserIO and eliminate all the previous array it found, and will return when all file has been read. If this is your intention then this is not the right way to do it as it is inefficient, because you keep creating arrays that will be discarded. If your intention is the last occurrence of line0 then you can just assign a found line to a String variable and when the iteration finishes just split and return that array as it will be the last occurrence of line0 in the file.
As i see it the only way that fed will return null is if there is no line with line0 in the file because search initializes the array if it finds line0 at least once in the file, this way feed will be an uninitialized array which will be a null pointer.
These lines has no meaning:
String nid00= null;
feed[0+s]= nid00;
String name00=null;
feed[1+s]= name00;
String age00= null;
feed[2+s]= age00;
String uname00= null;
feed[3+s]= uname00;
String upassword00= null;
feed[4+s]= upassword00;
I think you meant nid00 = feed[0+s] and so on, because the way you wrote the assignment to nid00 and the other variables will be always null which will be useless.
Also when you copy arrays try to use Arrays.copyOf methods or System.arraycopy they save you writing several lines and also they are more efficient, read about them in the documentation.
And the last thing, it is not useful to catch nullpointer exception if you wrote your code, in general you must know what your methods do and if there is a nullpointer exception in something you wrote then there is something wrong in your code, if for example a method you wrote returns null then you must know about the possibility of a null return and handle that possible return, this way it will be easier for you to read your code and use it and also for others who use your code.
The nullpointer you are getting is because you trying to get the length of an uninitialized feed inside fed method, you must be very careful.

How can I parse lines of data from file to populate objects for each?

I have a text file with the list inside, every line has data that I need insert in the new objects. So data looks like somename=3000 or another type with the slash data another type = 6000.
I have particular class "Item" that has String and int variable. Data need to be inserted into them. Every new object has to be added to the ArrayList<Item>.
// Calculate the lines for next for each loop
int lineCount = 0;
while (sc.hasNextLine()) {
lineCount++;
sc.nextLine();
}
for (int i = 0; i < lineCount; i++) {
// creating the object
Item item = new Item();
// add item object to items ArrayList
items.add(item);
// add line to String variable lineToString,
while (scaner.hasNextLine()) {
String lineToString = scaner.nextLine();
sc.nextLine();
}
So, I figured out that to do this, I need to
copy the whole line and put into some string variable;
split it for integer and string variable;
insert string parts to the String variable and numbers to the int variable in particular object that was created in iteration time of "for loop".
add the object with a data inside to the ArrayList.
I used Scanner to read a text file. When I try to insert the scaner.nextLine to the String it's doesn't work; I mean it's executing but variable String lineToString doesn't have the line from a text file.
Could somebody help with an idea of how better to proceed with this problem? Maybe there is some simpler way to insert the 2 different type of data from the text file line in the object and put it into the ArrayList? Every line in the text file has different data and has to be in different objects.
You didn't mention clearly the line format from the text file. I assume so far you have text file in which each line is like
someone=140000
And you are trying to read those lines of the text and parse each of them to an object of Item which contains a String property (I assume you name it name) and an int property (I assume you name it number)
If this is it, you fisrt need to read your text file line by line and process it further. There are several ways to read a text file line by line.
BufferReader
This is a very common and so far most appropriate way to read a text file in consider of performance.
List<Item> particulatItems = new ArrayList<>();
// using try-with-resource that will help closing BufferedReader by own
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
particularItems.add(processLine(line));
}
}
Scanner
You could use Scanner too.
try (Scanner scanner = new Scanner(new File(fileName))) {
while (scanner.hasNext()) {
particularItems.add(processLine(line));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
You should extract the line processing logic to a independent function. This is good practice of clean coding.
public static Item processLine(Strinng line) {
String[] tokens = line.split("=");
Item item = new Item(tokens[0], tokens[1]);
}
Assuming you have that particular object defined as Item and you are populating a List of this type
public class Item {
String name;
int number;
public Item(String name, String numtxt) {
this.name = name;
this.number = Integer.parseInt(numtxt);
}
// setter getter
}
More reading:
How to read a large text file line by line using Java?
Different ways of Reading a text file in Java
Difference between Scanner vs BufferReader
Try-with-resources in Java 7
Looks like you have already scanned full file in below code snippet:
while (sc.hasNextLine()) {
lineCount++;
sc.nextLine();
}
After this, you are again iterating in for-loop but with same scanner, which has read last line
So the following may return false:
while (scaner.hasNextLine())
I it may never enter while loop
You should reset scanner before iterating lines again .. or may be use something else than scanner to count lines
Apart from what #Ashish Mishra mentioned, you are doing the second while loop in a for loop, why? Isn't one loop sufficient?
int lineCount = 0;
while (sc.hasNextLine()) {
lineCount++;
String lineToString = sc.nextLine();
Item item = new Item();
//convert lineToString to item
items.add(item);
}

Why is the Scanner .next() method returning null?

I am reading input from 2 separate files using 2 different Scanner objects. I have 2 nested loops whose continuing condition depends on what the Scanner's .hasNext() method returns.
I am comparing the contents of each file. If there's a match, I would like to print it. However, my current code keeps returning null and I don't know why. Can you please tell me what I am doing wrong?
Scanner stdin1 = new Scanner("file1.txt");
Scanner stdin2 = new Scanner("file2.txt");
while(stdin1.hasNext()){
while(stdin2.hasNext()){
if(stdin1.next().equals(stdin2.next()){
//This line below is giving the error
System.out.println(stdin1.next() + " " + stdin2.next() );
}
}
}
your hasNext() method checks whether there are anymore elements or not. If it returns true, then it means that there is one more element which you can access using next() method.
In your code, for every hasNext(), you are calling next() two times which is not the correct way.
You should modify your code to somewhat like this:
Scanner stdin1 = new Scanner("file1.txt");
Scanner stdin2 = new Scanner("file2.txt");
while(stdin1.hasNext()){
while(stdin2.hasNext()){
Object one = stdin1.next();
Object two = stdin2.next();
if(one.equals(two)){
//This line below is giving the error
System.out.println(one + " " + two );
}
}
}
EDIT:
Note that next() doesn't returns null if there's no next token. This technique is to deal with the error java.util.NoSuchElementException which is thrown by the nextElement method of an Enumeration to indicate that there are no more elements in the enumeration. [source]
By "returning null" you mean the program prints nothing.
Two problems.
First, Scanner(String text) creates a scanner on the given string. It does not create a scanner to read a file of the given name. Instead, you should give it a File.
Scanner stdin1 = new Scanner(new File("file1.txt"));
Second, what's with the nested while loop? You should check both scanners before extracting tokens from them.
while (stdin1.hasNext() && stdin2.hasNext()) {
String one = stdin1.next();
String two = stdin2.next();
if (one.equals(two)) {
// print
}
}
// Now maybe one of them still got tokens, but we are printing
// the tokens that are equal, so doesn't matter.
Why your code prints nothing? Because stdin1.next() returns "file1.txt" and stdin2.next() returns "file2.txt".
I realized what you are trying to achieve is not what you are doing in your code.
The constructor Scanner(String source) does not take a File Name as input.
Use this constructor instead: Scanner(File file)
To achieve what you are doing, try this:
Update: The scanner object needs to be closed and re-opened inside the inner while loop, which is a unnecessary overhead due to multiple i/o operations. To avoid this, capture the elements into a list and then do the comparison. Try this piece of code:
Scanner stdin1 = new Scanner(new File("file1.txt"));
Scanner stdin2 = new Scanner(new File("file2.txt"));
List list1 = new ArrayList();
List list2 = new ArrayList();
while (stdin1.hasNext()) {
list1.add(stdin1.next());
}
while (stdin2.hasNext()) {
list2.add(stdin2.next());
}
for (Object o1 : list1) {
for (Object o2 : list2) {
if (o1.equals(o2)) {
System.out.println(o1 + " " + o2);
}
}
}
Hope this helps!
Two while loop is high time complexity, try to solve this with one loop, and close the program after execution.
public static void main(String[] args) {
Scanner stdin1 = null, stdin2 = null;
try {
stdin1 = new Scanner(new File("C:\\Users\\pechen\\Documents\\file1.txt"));
stdin2 = new Scanner(new File("C:\\Users\\pechen\\Documents\\file2.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (stdin1.hasNext()) {
if (stdin2.hasNext()) {
Object o = stdin1.next();
if (o.equals(stdin2.next())) {
System.out.println(o);
}
} else {
break;
}
}
}

Importing data from text

I have a bunch of text files with entries that look like this:
20662 = {
name="Durgulel"
dynasty=100603
martial=7
diplomacy=4
intrigue=5
stewardship=4
learning=6
religion="orthodox"
culture="alan"
trait="chaste"
trait="arbitrary"
trait="scholarly_theologian"
father=41592
992.1.1={
birth="992.1.1"
}
1068.1.1={
death="1068.1.1"
}
}
Is there a standard way for reading values from something like this into variables?
You could use a StreamTokenizer; should look roughly like this (untested):
static Map<String,Object> parse(
StreamTokenizer tokenizer, int endToken) throws IOException {
Map<String,Object> result = new TreeMap<String,Object>();
while (tokenizer.nextToken() != endToken) {
String key = tokenizer.sval;
if (tokenizer.nextToken() != '=') {
throw new RuntimeException("'=' expected");
}
if (tokenizer.nextToken() == '{') {
result.put(key, parse(tokenizer, '}'));
} else {
tokenizer.nextToken();
result.put(key, tokenizer.sval);
}
}
return result;
}
static void main(String[] args) throws IOException {
Reader reader = new FileReader(args[0]);
Map<String,Object> parsed = parse(
new StreamTokenizer(reader), StreamTokenizer.TT_EOF);
System.out.println(parsed);
}
p.s. This will need some additional handling for 922.1.1 and similar keys. If the format is really just line based, it might be more straight forward to use BufferedReader.readLine(), trim() and check for { / } / =
p.p.s If by variables you mean instance member variables, you could use the Java reflection API to set them accordingly (instead of reading to a map as in the example). You'd hand in the object to fill and then look up and set the members via object.getClass().getField(key).set(object, value)
Yes, there are a few ways to read files into a program. I'd recommend reading about BufferedReader, FileReader, and Scanner. Some documentation on the following:
FileReader
BufferedReader
Scanner
I usually pair BufferedReader and FileReader because the BuffereReader method nextLine() is conveniant for string variables. It's implemented as follows:
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
String x = br.readLine();
I'd also recommend some sort of regex expression for reading in your lines because of how the document is formatted. An example of an way of reading in seperate words into indices of a String[] with readLIne() and a simple regex expression is: String wH[] = br.readLine().split("\\W+"); This might be useful for splitting each line based on its contents, but since your lines don't appear to be separated by spaces, it always viable to just examine the raw string based in by readLine() in some sort of for-loop.
Once you've targeted the exact values you want, you can assign them to variables. For example, lets say you have a condition that detects the phrase "name" in a line, you could then assign the value that comes after the = and between the quotes to your desired variable. Then Rinse and Repeat.
Hope this helps.

To have efficient many-to-many relation in Java

How can you make the efficient many-to-many -relation from fileID to Words and from word to fileIDs without database -tools like Postgres in Java?
I have the following classes.
The relation from fileID to words is cheap, but not the reverse, since I need three for -loops for it.
alt text http://img191.imageshack.us/img191/4077/oliorakenne1.png
My solution is not apparently efficient.
Other options may be to create an extra class that have word as an ID with the ArrayList of fileIDs.
Reply to JacobM's answer
The relevant part of MyFile's constructors is:
/**
* Synopsis of data in wordToWordConutInFile.txt:
* fileID|wordID|wordCount
*
* Synopsis of the data in the file wordToWordID.txt:
* word|wordID
**/
/**
* Getting words by getting first wordIDs from wordToWordCountInFile.txt and then words in wordToWordID.txt.
*/
InputStream in2 = new FileInputStream("/home/dev/wordToWordCountInFile.txt");
BufferedReader fi2 = new BufferedReader(new InputStreamReader(in2));
ArrayList<Integer> wordIDs = new ArrayList<Integer>();
String line = null;
while ((line = fi2.readLine()) != null) {
if ((new Integer(line.split("|")[0]) == currentFileID)) {
wordIDs.add(new Integer(line.split("|")[6]));
}
}
in2.close();
// Getting now the words by wordIDs.
InputStream in3 = new FileInputStream("/home/dev/wordToWordID.txt");
BufferedReader fi3 = new BufferedReader(new InputStreamReader(in3));
line = null;
while ((line = fi3.readLine()) != null) {
for (Integer wordID : wordIDs) {
if (wordID == (new Integer(line.split("|")[1]))) {
this.words.add(new Word(new String(line.split("|")[0]), fileID));
break;
}
}
}
in3.close();
this.words.addAll(words);
The constructor of Word is at the paste.
Wouldn't a more efficient approach be to assign the link from Word to MyFile at the point that you know the Word is in the File? That is to say, how do you build the list of Words in the MyFile object? If you're reading the words in to the MyFile out of, say, a file on the filesystem, than as you read in each word, you assign its MyFile to the current file.
//within MyFile constructor or setter for Words
while (//there's another word to add) {
Word newWord = new Word(//read word from file);
words.add(newWord);
newWord.setMyFile(this);
}
This is akin to the typical way to manage a bidirectional parent-child relationship:
//in Parent
public void addChild(Child child) {
myChildren.add(child);
child.setParent(this);
}
It might help if you show us how you build the MyFile object.
Edited after you added the code that builds the list of Words:
OK, so having seen the code that builds your Words, I don't think setting up the relationship is the source of your inefficiencies. It looks like you are setting up the relationship in exactly the way I suggested (as you add each word, you give that word the fileID of the corresponding file).
It looks like the source of your inefficiencies are that, for each word, you have to match it up with various things that you currently have in a set of files (e.g. WordToWordId). So for every word you have to loop through every line of that file, and find the match. This is certainly inefficient.
The better approach is to have those pairings in memory in a HashMap, initialized at startup. That way, if you have a particular word and need the corresponding ID, or vice versa, you look them up in your HashMap, which is a constant-time operation. Similarly, for each word, you are looping through every file; again, do that loop ONCE, and store the result in a HashMap. Then lookups become constant time.
Both classes should override hashCode and equals. Thus you will decide what is equal.
Then you will create a set in each of your classes.
public class MyFile implements Comparable<MyFile> {
//your fields here
Set<Word> words = new HashSet<Word>(0);
//Remember to override hashCode and equals
}
public class Word implements Comparable<Word> {
//your fields here
Set<MyFile> words = new HashSet<MyFile>(0);
//Remember to override hashCode and equals
}
In your sets now you will have all the MyFiles.words and otherway around, all the Words.myFile
I think you want that the file know it's words and the words know the files where it is used.
public class File {
private List<Word> words;
public File(){
words=new Vector<Word>();
}
/**
*The method add word to word list.
**/
public addWord(Word word){
this.words.add(word);
word.addFile(this);
}
}
public class Word{
List<File> files;
public addFile(File file){
this.files.add(file);
}
}
or vice versa... but you should question GRASP Design pattern.Maybe your data type is wrong (I dont say wrong because itis your desing,so i respect).

Categories