I need to use ArrayLists to count the words in a text file and display their frequency. I would like to start by creating the ArrayList of "Word" objects. From that point I shouldn't have an issue. The problem I am encountering is when adding an object to the list. I receive an error stating "The method add(Word) in the type ArrayList is not applicable for the arguments (String)"
public ArrayList<Word> wordList = new ArrayList<Word>();
String fileName, word;
int counter;
Scanner reader = null;
Scanner scanner = new Scanner(System.in);
public void analyzeText() {
System.out.print("Please indicate the file that you would like to analyze (with the path included): ");
fileName = scanner.nextLine();
try {
reader = new Scanner(new FileInputStream(fileName));
}
catch(FileNotFoundException e) {
System.out.println("The file could not be found. The program will now exit.");
System.exit(0);
}
while (reader.hasNext()) {
word = reader.next().toLowerCase();
wordList.add(word);
counter++;
}
}
public class Word {
String value;
int frequency;
public Word(String v) {
value = v;
frequency = 1;
}
}
You need to add a Word Object not a String:
word = reader.next().toLowerCase();
Word myNewWord = new Word(word); /*Generates a Word Object using your constructor*/
wordList.add(myNewWord);
counter++
Hope that helps.
wordList is an array of "Word" objects. But in line 17
wordList.add(word);
you're adding another type of content into the array (a string).
Note there's an object-type, named "Word" (uppercase), and another variable named
"word" (lowercase) of type string.
You're adding a string "word" to the array list, but in this case you can add only objects "Word" to the ArrayList of name wordList.
You need to add Word object to your list. But you are assigning a string which is readed from scanner. You need to create a Word object.
I think, your solution for counting word is wrong. You are using wrong data structure. Hashmap fits better for this case. You can assign words as a key and count of words as a value.
Related
I have an ArrayList,where I search for needed element and then add the needed part of it to another ArrayList. The problem is that if I want to keep searching for the words,not only one word,I don't know how to keep going on the elements through the loop. With the using of iterator, I wouldn't be able to search for things I need.
public static ArrayList<String> FindWord(){
ArrayList<String> rewrite=new ArrayList<>();//
ArrayList<String> word=Reading();// rewrites the data from one string to other
String userinput=Chat();
for(String elmt:word){
if (elmt.contains(userinput) && elmt.contains("=")) {
String[] parts=elmt.split("\\=");
rewrite.add(parts[1]);
// here I must do something like word.next
}
}
System.out.println(rewrite);
return rewrite; // RETURNS THE SYNONIM OF THE WORD
}
So,it goes like if I input "hello", it will find me the word "greeting",which is a synonim in my text file. If I input "awesome", it will find the word "thanks", but if I input both of them it will input an empty array, like nothing is found instead of " greeting, thanks"
UPD:
The Reading() returns:
public static ArrayList<String> Reading() {
Scanner inputreader = null;
try {
inputreader = new Scanner(new FileInputStream("D:\\sinonims.txt"));
}catch (FileNotFoundException e1) { // OPENS FILE WITH SINONIMS
e1.printStackTrace();
System.out.println("File not found");
System.exit(0);
}
ArrayList<String> Sins=new ArrayList();
while(inputreader.hasNextLine()){
String l=inputreader.nextLine();
Sins.add(l); // REWRITES DATA FROM FILE TO ARRATLIST
}
inputreader.close();
System.out.print(Sins);
return Sins;
}
public static String Chat(){
System.out.println("Let's start talking.");
Scanner in=new Scanner(System.in);
String line=in.nextLine();
return line;
}
If you are trying to accept many inputs, you'll need to loop around the input & for loop.
The for loop already loops over all the words.
Note: I replaced contains for startsWith to prevent you catching the word on the other side of the equals
static ArrayList<String> word=Reading();
public static ArrayList<String> FindWord(){
ArrayList<String> rewrite=new ArrayList<>();
String userinput = "" ;
while (true) {
userinput=Chat();
if (userinput.equals("quit")) break;
for(String elmt:word){
if (elmt.startsWith(userinput) && elmt.contains("=")) {
String[] parts=elmt.split("\\=");
rewrite.add(parts[1]);
}
}
System.out.println(rewrite);
return rewrite; // RETURNS THE SYNONIM OF THE WORD
}
I can't really say this is the best way to approach your problem because it seems you need a Hashmap, not an Arraylist
contains fetches you exact match, split the text and match accordingly, store the results in new array list
you can create another arraylist and add your userinput values one by one into that list . you can iterate this newly created arraylist by using new for each loop on top of the current for each loop.
You should split the input string userinput with some specific delimiter.
Then for each word, Iterate through the splitted array and give each word as input , Find its Synonym with your technique and add it to the arraylist.
This can be implemented by doing some changes in your code.
public static ArrayList<String> FindWord()
{
ArrayList<String> rewrite=new ArrayList<>();
ArrayList<String> word=Reading();
String userinput=Chat();
String inputs[]=userinput.split(","); //Considering delimiter is comma(",") in user input
for(String input : inputs) //Giving each word as input at a time and search for it in word String
{
for(String elmt:word)
{
if (elmt.contains(input) && elmt.contains("="))
{
String[] parts=elmt.split("\\=");
rewrite.add(parts[1]);
}
}
}
System.out.println(rewrite);
return rewrite; // RETURNS THE SYNONIM OF THE WORD
}
So Here I am considering that the input is with delimiter Comma(",") so I have splitted input string with Comma(",") as you have given description in comments about your problem with space as delimiter.
When you will print the ArrayList, Automatically Output will be printed in separated manner with comma(, ).
So for Input : hello,awesome It will give output as greeting, thanks.
I want to make an user database, which creates a new variable from the string that was entered in the console. I don't know if this is possible and i've searched everywhere.
You can use data structures like a List, which can hold a number of objects. A list grows when you add objects to them. A simple list to get started with is java.util.ArrayList.
Example to get you started:
// create a new list which can hold String objects
List<String> names = new ArrayList<>();
String nextName = scanner.nextLine();
// read names until the user types stop
while(!nextName.equals("stop")) {
// add new name to the list. note: the list grows automatically.
names.add(nextName);
// read next name from user input
nextName = scanner.nextLine();
}
// print out all names.
for(String name : names) {
System.out.println(name);
}
Sure, like this:
// 1. Create a Scanner using the InputStream available.
Scanner scanner = new Scanner( System.in );
// 2. Don't forget to prompt the user
System.out.print( "Type some data for the program: " );
// 3. Use the Scanner to read a line of text from the user.
String input = scanner.nextLine();
// 4. Now, you can do anything with the input string that you need to.
// Like, output it to the user.
System.out.println( "input = " + input );
There are ways to do what you asked using Reflection. But that leads to a lot of problems and design issues.
Instead, try using a Key/Value store of some sort, and a simple class like this:
public class KeyValueField
{
public final String Key;
public final String Value;
public KeyValueField(String key, String value)
{
Key = key;
Value = value;
}
}
Usage like this:
System.out.print("Enter field name:");
String key= System.console().readLine();
System.out.print("Enter field value:");
String value = System.console().readLine();
KeyValueField newField = new KeyValueField(key, value);
I recomend using a Hashmap.
import java.util.HashMap;
HashMap<String, String> keyValue = new HashMap<String, String>();
keyValue.put(key, value);
I am trying to figure out how to go about searching some user input for multiple keywords.The keywords come from a hash map called Synonym. So basically I enter some sentence and if the sentence contains one or more keywords or keyword synonyms I want to call a parse file method. So far I could only search for one keyword. I am stuck trying to get a user input which could be a long sentence or just one word containing the keyword(s) and search the hash map key for that matching word. For example, If the hash map is
responses.put("textbook name", new String[] { "name of textbook", "text", "portfolio" });
responses.put("current assignment", new String[] { "homework","current work" });
and the user inputs " what is the name of textbook that has the homework" I want to search a text file for textbook current assignment. Assuming that the text file contains the sentence The current assignment is in the second textbook name ralphy". I mean i got most of my implementation done, the issue is dealing with more than one keyword. Can someone help me solve this?
Here is my code
private static HashMap<String, String[]> responses = new HashMap<String, String[]>(); // this
public static void parseFile(String s) throws FileNotFoundException {
File file = new File("data.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
final String lineFromFile = scanner.nextLine();
if (lineFromFile.contains(s)) {
// a match!
System.out.println(lineFromFile);
// break;
}
}
}
private static HashMap<String, String[]> populateSynonymMap() {
responses.put("test", new String[] { "test load", "quantity of test","amount of test" });
responses.put("textbook name", new String[] { "name of textbook", "text", "portfolio" });
responses.put("professor office", new String[] { "room", "post", "place" });
responses.put("day", new String[] { "time", "date" });
responses.put("current assignment", new String[] { "homework","current work" });
return responses;
}
public static void main(String args[]) throws ParseException, IOException {
/* Initialization */
HashMap<String, String[]> synonymMap = new HashMap<String, String[]>();
synonymMap = populateSynonymMap(); // populate the map
Scanner scanner = new Scanner(System.in);
String input = null;
/*End Initialization*/
System.out.println("Welcome To DataBase ");
System.out.println("What would you like to know?");
System.out.print("> ");
input = scanner.nextLine().toLowerCase();
String[] inputs = input.split(" ");
for (String ing : inputs) { // iterate over each word of the sentence.
boolean found = false;
for (Map.Entry<String, String[]> entry : synonymMap.entrySet()) {
String key = entry.getKey();
String[] value = entry.getValue();
if (input.contains(key) || key.contains(input)|| Arrays.asList(value).contains(input)) {
found = true;
parseFile(entry.getKey());
}
}
}
}
Any help would be appreciated
I have answered very similar question Understand two or more keys with Hashmaps. But I'll make my point more clear. In the current set of datastructures that you have used lets consider the following structures
1) Input List --> Spilt words in the sentence (may be in order) and keep it in a list example [what,is,the,name,of,textbook,that,has,the,homework]
2) Keyword list --> All keys from the Hashmap database you are using example [test,textbook name,professor office]
Now you have to set some criteria by which you say I can have max 3 words phrase out of sentence (example 'name of textbook')as keyword, why this criteria - to limit the processing, otherwise you'll end up checking lot of combinations of input.
Once you have this, you check whats common in input list and keyword list for criteria you have set. If you don't set criteria then you may try all the combinations against the key set.Once you find single or multiple match, output the synonym list etc.
Example check [name of textbook] against all your keys of the map.
If you want to reverse check, the do the same process by creating a list of synonyms and checking it.
My two tips tackling this problem
1) Define set of keywords and don't check with value list, Hash map structure is not good for that. In this be prepared for redundant data.
2) Set how many words in order you want to search in this keyset. And preferably only keep distinct words.
Hope this helps!
You could use a single regex pattern per "dictionary entry" and test each pattern against your input. Depending on your performance requirements and the size of your dictionary and input, it might be a good solution.
If you're using java 8, try this:
public static class DicEntry {
String key;
String[] syns;
Pattern pattern;
public DicEntry(String key, String... syns) {
this.key = key;
this.syns = syns;
pattern = Pattern.compile(".*(?:" + Stream.concat(Stream.of(key), Stream.of(syns))
.map(x -> "\\b" + Pattern.quote(x) + "\\b")
.collect(Collectors.joining("|")) + ").*");
}
}
public static void main(String args[]) throws ParseException, IOException {
// Initialization
List<DicEntry> synonymMap = populateSynonymMap();
Scanner scanner = new Scanner(System.in);
// End Initialization
System.out.println("Welcome To DataBase ");
System.out.println("What would you like to know?");
System.out.print("> ");
String input = scanner.nextLine().toLowerCase();
boolean found;
for (DicEntry entry : synonymMap) {
if (entry.pattern.matcher(input).matches()) {
found = true;
System.out.println(entry.key);
parseFile(entry.key);
}
}
}
private static List<DicEntry> populateSynonymMap() {
List<DicEntry> responses = new ArrayList<>();
responses.add(new DicEntry("test", "test load", "quantity of test", "amount of test"));
responses.add(new DicEntry("textbook name", "name of textbook", "text", "portfolio"));
responses.add(new DicEntry("professor office", "room", "post", "place"));
responses.add(new DicEntry("day", "time", "date"));
responses.add(new DicEntry("current assignment", "homework", "current work"));
return responses;
}
Sample output:
Welcome To DataBase
What would you like to know?
> what is the name of textbook that has the homework
textbook name
current assignment
Make a list/append the keys that match. As for the given example , when keyword "textbook" matches store it in a "temp" variable. Now, continue the loop, now keyword "current" matches , append this to variable temp. So, now temp contains "textbook current". Similairly, continue and append the next keyword "assignment" into "temp".
Now, temp contains "textbook current assignment".
Now at the end call the parseFile(temp).
This should work for single or multiple matches.
//Only limitation is the keys are to be given in a ordered sequence , if you want
// to evaluate all the possible combinations then better add all the keys in a list
// And append them in the required combination.
//There might be corner cases which I havent thought of but this might help/point to a more better solution
String temp = "";
//flag - used to indicate whether any word was found in the dictionary or not?
int flag = 0;
for (String ing : inputs) { // iterate over each word of the sentence.
boolean found = false;
for (Map.Entry<String, String[]> entry : synonymMap.entrySet()) {
String key = entry.getKey();
String[] value = entry.getValue();
if (input.contains(key)) {
flag = 1;
found = true;
temp = temp +" "+ key;
}
else if (key.contains(input)) {
flag = 1;
found = true;
temp = temp +" "+ input;
}
else if (Arrays.asList(value).contains(input)) {
flag = 1;
found = true;
temp = temp +" "+ input;
}
}
}
if (flag == 1){
parseFile(temp);
}
I have an object Movie which contains these data members: title(string), year(int), and list of actors(ArrayList). I want to read from the file and create a new Movie object with the information from the file. This is an example text from the file:
Star Wars/1977/Mark Hamill,Carrie Fisher,Harrison Ford
How would I add the file to the tree to meet the conditions of my Constructor:
public class Movie {
private String title;
private int year;
private ArrayList<String> actors;
public Movie( String t, int y, ArrayList<String> a ){
title = t;
year = y;
actors = a;
}
How I am trying to add File (I know it would work if everything was of type String):
try{
Scanner read = new Scanner( new File("movies.txt") );
do{
String line = read.nextLine();
String [] tokens = line.split("/");
//How would I change this to allow for differnt data types.
tree.add( new Movie(tokens[0], tokens[1], tokens[2] );
}while( read.hasNext() );
read.close();
}catch( FileNotFoundException fnf){
System.out.println("File not found.");
}
I am thinking I would need to create my ArrayList here as well as an int.
Convert the type.
1) convert the tokens[1] into integer by using Integer.parseIt(tokens[1]);
2) for array list again spilt the tokens[2] by "," and add it to an arraylist. Use arraylist.add() for adding the values in the arraylist.
3) call the constructor using string int and arraylist variables.
Your Question is not clear, but any way you can add this if I correctly understand you
tree.add( new Movie(tokens[0], Integer. Integer.parseInt(tokens[1]),Arrays.asList(tokens[2].split(",") );
So I have a problem that takes the names of people from a user and stores them in an ArrayList(personalNames). After that I need to take that list and remove any name that has anything besides letters a-z (anything with numbers or symbols) in it and put them into a separate ArrayList(errorProneNames) that holds the errors. Could someone help me with the removal part?
public class NameList {
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
Scanner input = new Scanner(System.in);
String answer;
do{
System.out.println("Enter the personal Names: ");
String names = input.next();
personalNames.add(names);
System.out.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
ArrayList<String> errorProneNames = new ArrayList<String>();
}
}
If it's the "how do I remove an element from an ArrayList<>" part which is causing problems, and you want to check all the values, you probably want to use an Iterator and call remove on that:
for (Iterator<String> iterator = personalNames.iterator(); iterator.hasNext(); ) {
String name = iterator.next();
if (isErrorProne(name)) {
iterator.remove();
}
}
Note that you mustn't remove an element from a collection while you're iterating over it in an enhanced-for loop except with the iterator. So this would be wrong:
// BAD CODE: DO NOT USE
for (String name : personalNames) {
if (isErrorProne(name)) {
personalNames.remove(name);
}
}
That will throw a ConcurrentModificationException.
Another option would be to create a new list of good names:
List<String> goodNames = new ArrayList<>();
for (String name : personalNames) {
if (!isErrorProne(name)) {
goodNames.add(name);
}
}
Now, if your real problem is that you don't know how to write the isErrorProne method, that's a different matter. I suspect that you want to use a regular expression to check that the name only contains letters, spaces, hyphens, and perhaps apostrophes - but you should think carefully about exactly what you want here. So you might want:
private static boolean isErrorProne(String name) {
return !name.matches("^[a-zA-Z \\-']+$");
}
Note that that won't cope with accented characters, for example. Maybe that's okay for your situation - maybe it's not. You need to consider exactly what you want to allow, and adjust the regular expression accordingly.
You may also want to consider expressing it in terms of whether something is a good name rather than whether it's a bad name - particularly if you use the last approach of building up a new list of good names.
Here is your solution :
String regex = "[a-zA-Z]*";
for (String temp : personalNames ) {
if (!temp.matches(regex)){
errorProneNames.add(temp);
personalNames.remove(temp);
}
}
You can use the remove() method of ArrayList
personalNames.remove("stringToBeRemoved");
Lot of overloaded methods are available. You can delete with index, Object(String itself) etc. You can see Javadocs for more info.
Also to remove all String having anything but a-z letters you can use regex. Logic is as follows
String regex = "[a-zA-Z]*";
String testString = "abc1";
if(!testString.matches(regex)){
System.out.println("Remove this");
}
As Jon pointed out while iterating over the List do not use the Lists's remove() method but the iterators remove() method.
There are two ways you can do this:
The first is to iterate backwards through the list, remove them, then add them into the second list. I say to do it backwards, because it will change the index.
for (int i = personalNames.size()-1; i >=0; i++) {
if (isBadName(personalNames.get(i)]){
errorProneNames.add(personalNames.get(i));
personalNames.remove(i);
}
}
The second way is to use the Iterator provided by ArrayList (personalNames.iterator()). This will allow you to go forward.
I would probably do this
// Check that the string contains only letters.
private static boolean onlyLetters(String in) {
if (in == null) {
return false;
}
for (char c : in.toCharArray()) {
if (!Character.isLetter(c)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
ArrayList<String> errorProneNames = new ArrayList<String>(); // keep this list here.
Scanner input = new Scanner(System.in);
String answer;
do {
System.out.println("Enter the personal Names: ");
String names = input.next();
if (onlyLetters(names)) { // test on input.
personalNames.add(names); // good.
} else {
errorProneNames.add(names); // bad.
}
System.out
.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
}
get an iterator from list, while itr has next element give it to a method for example isNotProneName which takes a String and returns true or false, if the given String matches not your needs. if false returned remove string from itr and add it to the other list
Use regex [a-zA-Z ]+ with String.matches to test error-prone name and Iterator to remove.
Iterator<String> it=personalNames.iterator();
while(it.hasNext()){
String name=it.next();
if(name.matches("[a-zA-Z ]+")){
it.remove();
}
}