This is a follow on to a couple questions I've already asked. Earlier I asked how to use a method to determine if elements of one list were present in another. The reason I did this is because I would like like to determine if one list contains anagrams of the other - using user input and a dictionary list. I'm having trouble determining this. I want to pass the lists into a method to determine if one contains the elements of another. Right now it only returns false when I know there is a real anagram present.
Could someone look at my code and help me figure it out? Also, how would I modify this to determine if user input contained multi-word anagrams?
My algorithm works by taking in the two lists and alphabetizing the letters in each word. I'd read about this method in another post and decided to go with it - it remains a work in progress. Here is my code:
public class AnagramSolver1 {
public static void main(String[] args) throws IOException {
//Scanner/Reader
Scanner scan = new Scanner(System.in);
BufferedReader in = new BufferedReader(new FileReader("src/dictionary.txt"));
//Lists to contain unsorted dictionary and input and after alphabetical sort
List<String> dictionary = new ArrayList<String>();
List<char[]> dictionarySort = new ArrayList<char[]>();
List<String> inputList = new ArrayList<String>();
List<char[]> inputSort = new ArrayList<char[]>();
String line = null;
//read in dictionary then sort alphabetically////
while (null!=(line=in.readLine()))
{
dictionary.add(line);
}
in.close();
dictionarySort = sortList(dictionary);
//print statement
/*
for(int i = 0; i < dictionarySort.size(); i++){
System.out.println(dictionarySort.get(i));
}*/
//User input, scan in then sort alphabetically////
System.out.println("Enter Word: ");
String input = scan.next();
inputList.add(input);
inputSort = sortList(inputList);
//print statement
/*
for(int i = 0; i < inputSort.size(); i++){
System.out.println(inputSort.get(i));
}*/
//determine if user input is an angram of any dictionary word
boolean isAnagram = isAnagram(dictionarySort, inputSort);
System.out.println(isAnagram);
}
//sort a string into a char array
public static List<char[]> sortList (List<String>sort){
List<char[]> sortList = new ArrayList<char[]>();
char[] letterSort;
for (int i = 0; i < sort.size(); i++) {
letterSort = sort.get(i).toCharArray();
Arrays.sort(letterSort);
sortList.add(letterSort);
}
return sortList;
}
//Determines if User input is an Anagram or not.
public static boolean isAnagram (List<char[]>dictionarySort, List<char[]>inputSort){
for (char[] c : dictionarySort) {
if (inputSort.contains(c)) {
return true;
}
}
return false;
}
}
There's a major bug here:
for (char[] c : dictionarySort) {
if (inputSort.contains(c)) { // BUG!
This won't work like you think it will. This tests if the exact same char[] object is contained in the list; it does not test if a char array that has the same characters is there.
To work the way you intend, don't store char[], store Strings.
To turn a char[] into a String, do this:
char[] c;
String s = new String(s);
Once you have sorted your chars in an array, turn the char array into a String and store that in your lists. It means that all Lists should be lists of List<String>.
If you want to determine if one word is an anagram of another, sort the letters of both words and the resulting strings must be equal if the words are anagrams.
Try this:
When loading your dictionary, sort the letters of each word. Store the sorted value as well as the dictionary value. Consider storing the dictionary words in a hash map that uses the sorted value as the key and has multiple words as the value.
Sort the letters of the user input.
Search the dictionary (possibly the map) using the sorted user input.
When displaying anagrams from your dictionary, be sure to remove the user input from the list of anagrams (blam is not an anagram of blam).
There are two ways (that I know) to put multiple values in a HashMap.
Store a List as the value and add to it as you read the dictionary.
Use a MultiMap (google has some available; I think the project is guava).
Your problem is that the contains from the list interface implements equals(), in the case of arrays what is being compared is the memory address of the two char[]'s. What you need to do is:
Option 1) Get your program to compare with the elements in dictionary against input using Arrays.equals(char[] one, char[] two), that will compare the contents.
Option 2) Instead of comparing the char[] get it to a point where you are comparing strings, using the string's equals() method which will also compare the contents.
Related
I'm doing a project were I need to remove letters systematically from an ArrayList as they show up in the words that the user puts in. Then all the remaining characters are displayed and then the elimination process continues until only vowels are left.
I cant seem to get it to eliminate the characters without the program crashing.
Here's the problematic code:
public static void Mapper(){
Scanner make = new Scanner(System.in);
char Aphabets[] ={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
ArrayList<Character> Alpabets = new ArrayList<>();
String word = make.nextLine();
for (int i = 0; i < Aphabets.length; i++) {
Alpabets. add(i,Aphabets[i]);
}
for (int i = 0; i < word.length(); i++) {
Alpabets.remove(word.charAt(i));
}
System.out.println(Alpabets);
}
Change
Alpabets.remove(word.charAt(i));
to
Alpabets.remove((Object) word.charAt(i));
The issue is that List.remove has two implementations (it's an overloaded method):
One implementation that takes an index as argument: List.remove(int index) ("remove the 5th element from the list")
One that removes an actual object from the list List.remove(Object o) ("remove the number 5 from the list).
By calling using Alpabets.remove(word.charAt(i)); you're accidentally invoking the one that takes an index, and if you give it a "large enough" character (characters can be seen as numerical values in Java), you'll hit an index out of bounds in the remove method.
By casting the argument to Object, you force the correct method to be called.
Might you can also use map key and value and remove based on user input.
Background to question
I have been working on developing code that is able to read a string, compress it an send it to a new file in a compressed form. (e.g. "hello, hello" -> "hello[0, 1]) and this works great at the moment. Here is the link for anyone who wants to use it: https://pastebin.com/v6YF34mU . The next stage is being able to re-create the file using the indexes and the words.
Question
I currently have got this code:
public static void main(String[] args) {
// TODO code application logic here
Pattern seaPattern = Pattern.compile("(.*?)\\[(.*?)\\],");
String compressedSea = "see[2, 4, 5],sea[0, 1, 3],";
Matcher seaMatcher = seaPattern.matcher(compressedSea);
while (seaMatcher.find()) {
String seaWords = seaMatcher.group(1);
String[] seaIndexes = seaMatcher.group(2).split(", ");
for (String str : seaIndexes) {
int seaIndex = Integer.parseInt(str);
System.out.print(seaIndex);
}
In short. I reads the string and splits it up into to different arrays. One of the arrays contains the indexes and the other contains the words. The next stage is putting these together and creating 1 string that is able to be compressed. I am relatively new to Java so I am not completely sure how I would go about doing this.
If anyone has got any ideas on how to do this it would be much appreciated!
I would suggest you to create a class for combining your word and indexes.
I have posted a suggestion below:
Updated answer after OP clarified what he wanted to output
public static void main(String[] args) throws FileNotFoundException {
Map<Integer, String> wordMap = new HashMap<Integer, String>();
Pattern seaPattern = Pattern.compile("(.*?)\\[(.*?)\\],");
String compressedSea = "see[2, 4, 5],sea[0, 1, 3],";
Matcher seaMatcher = seaPattern.matcher(compressedSea);
while (seaMatcher.find()) {
String word = seaMatcher.group(1);
String[] seaIndexes= seaMatcher.group(2).split(", ");
for(String s : seaIndexes){
wordMap.put(Integer.valueOf(s), word);
}
}
//HashMap will printout ordered by the key value.
//This is because the key is an Integer
//The hashed key value is therefore the key value itself.
System.out.println(wordMap);
}
Output
{0=sea, 1=sea, 2=see, 3=sea, 4=see, 5=see}
Bonus
If you want to iterate though the HashMap, you can do the following:
Iterator it = wordMap.entrySet().iterator();
while(it.hasNext()){
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getValue());
}
Output
sea
sea
see
sea
see
see
If I understood it correctly.
Create a new array with the highest index in index array.
String[] finalString = new Array[highestIndex];
now loop through your words array
for(String str: wordsArray){
//grab the index of each str
//put your str in the new array at the same indexes
finalString [index] = str;
}
}
Are you just asking how to put two strings into one string? Or am I understanding wrong?
If it's just adding two strings, that can be done by using the + sign.
String newString = string1 + string2;
If you're asking how to put them into a hashmap (so key-value pair), that would be:
HashMap<Integer, String> map = new HashMap<>();
map.put(value, word);
What I'm trying to do is to declare a certain amount of strings according to the amount of tokens a scanner scans in a single input, then have these strings equal the next input. This is what I'm trying:
int numberOfTokens = 0;
boolean mainLoop = true;
Scanner input = new Scanner(System.in);
while(mainLoop == true)
{
while(input.hasNext())
{
String int(+ numberOfTokens) = input.next(); (this doesn't work)
numberOfTokens += 1;
}
}
I hope I made it clear of what I am trying to do. I tried using String arrays, but they won't work for what i'm trying to do.
Thanks.
You can do:
String[] myStringArray = new String[abc];
where abc is an integer you get from user
and then
myStringArray[index] = input.next();
and index must be a valid number between 0 and abc
If you don't know in advance how many strings you will need to store then an array is a poor choice of data structure, at least during the input phase. Use a List instead -- these keep the elements in order, yet expand as needed to accommodate new elements. They are convenient to work with overall, but if you ultimately must get the strings in array form (e.g. because some external API requires that form) then it is easy to obtain the corresponding array.
For example:
List<String> tokens = new ArrayList<>();
while (input.hasNext()) {
tokens.add(input.next());
// a List keeps track of its own length
}
If you later wanted the array then you could do
String[] tokenArray = tokens.toArray(new String[0]);
The number of tokens recorded in the List is available at any time as tokens.size(), or after you convert to an array, as tokenArray.length.
In any event, you cannot create new variables at runtime in Java.
Instead of string variables, you should declare one variable like this before the while loop.
List<String> tokens = new ArrayList<>();
while (input.hasNext()) {
tokens.add(input.next());
}
You can then operate on the tokens, like this:
int n = tokens.size();
for (String token : tokens) {
System.out.println(token);
}
import java.io.*;
import java.util.*;
public class ListSetMap2
{
public static void main(String[] args)
{
Map<String, Integer> my_collection = new HashMap<String, Integer>();
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter a file name");
String filenameString = keyboard.nextLine();
File filename = new File(filenameString);
int word_position = 1;
int word_num = 1;
try
{
Scanner data_store = new Scanner(filename);
System.out.println("Opening " + filenameString);
while(data_store.hasNext())
{
String word = data_store.next();
if(word.length() > 5)
{
if(my_collection.containsKey(word))
{
my_collection.get(my_collection.containsKey(word));
Integer p = (Integer) my_collection.get(word_num++);
my_collection.put(word, p);
}
else
{
Integer i = (Integer) my_collection.get(word_num);
my_collection.put(word, i);
}
}
}
}
catch (FileNotFoundException e)
{
System.out.println("Nope!");
}
}
}
I'm trying to write a program where it inputs/scans a file, logs the words in a HashMap collection, and count's the times that word occurs in the document, with only words over 5 characters being counted.
It's a bit of a mess in the middle, but I'm running into issues on how to count the number of times that word occurs, and keeping a individual count for each word. I'm sure there is a simple solution here and I'm just missing it. Please help!
Your logic of setting the frequency of word is wrong. Here is a simple approach that should work for you:
// if the word is already present in the hashmap
if (my_collection.containsKey(word)) {
// just increment the current frequency of the word
// this overrides the existing frequency
my_collection.put(word, my_collection.get(word) + 1);
} else {
// since the word is not there just put it with a frequency 1
my_collection.put(word, 1);
}
(Only giving hints, since this seems to be homework.) my_collection is (correctly) a HashMap that maps String keys to Integer values; in your situation, a key is supposed to be a word, and the corresponding value is supposed to be the number of times you have seen that word (frequency). Each time you call my_collection.get(x), the parameter x needs to be a String, namely the word whose frequency you want to know (unfortunately, HashMap doesn't enforce this). Each time you call my_collection.put(x, y), x needs to be a String, and y needs to be an Integer or int, namely the frequency for that word.
Given this, give some more thought to what you're using as parameters, and the sequence in which you need to make the calls and how you need to manipulate the values. For example, if you've already determined that my_collection doesn't contain the word, does it make sense to ask my_collection for the word's frequency? If it does contain the word, how do you need to change the frequency before putting the new value into my_collection?
(Also, please choose a more descriptive name for my_collection, e.g. frequencies.)
Try this way -
while(data_store.hasNext()) {
String word = data_store.next();
if(word.length() > 5){
if(my_collection.get(word)==null) my_collection.put(1);
else{
my_collection.put(my_collection.get(word)+1);
}
}
}
I am creating a program that lets you store 10 items in an array. What I haven't been able to get the program to do is give an error if one of the entered items already exists in the array.
So, for example, if the array looks like [banana, potato, 3, 4, yes, ...] and I enter banana again, it should say "Item has already been stored" and ask me to re-enter the value. The code I currently have is:
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int stringNumber = 0;
String[] stringArray = new String[10];
for (int i = 0; i <= stringArray.length; i++) {
out.println("\nEnter a string");
String input = keyboard.next();
stringArray[stringNumber] = input;
out.println("\"" + stringArray[stringNumber] + "\"" + " has been stored.");
PrintArray(stringArray);
stringNumber++;
You can use nested loops to go through the array to see if the new input exists. It would be better to do this in a function. Also when doing this you need to make sure that you are not at the first element or you will get a null pointer exception.
for (int i = 0; i <= stringArray.length; i++) {
boolean isInArray = false;
System.out.println("\nEnter a string");
String input = keyboard.next();
if (i > 0) {
for (int j = 0; j < stringArray.length; j++) {
if (stringArray[j].equalsIgnoreCase(input)) {
isInArray = true;
break;
}
}
}
if (!isInArray) {
stringArray[stringNumber] = input;
} else {
System.out.println("\"" + stringArray[stringNumber-1] + "\""
+ " has been stored.");
}
PrintArray(stringArray);
stringNumber++;
}
It's always better to use a HashSet when you don't want to store duplicates. Then use HashSet#contains() method to check if element is already there. If ordering is important, then use LinkedHashSet.
If you really want to use an array, you can write a utility method contains() for an array. Pass the array, and the value to search for.
public static boolean contains(String[] array, String value) {
// Iterate over the array using for loop
// For each string, check if it equals to value.
// Return true, if it is equal, else continue iteration
// After the iteration ends, directly return false.
}
For iterating over the array, check enhanced for statement.
For comparing String, use String#equals(Object) method.
When you got the String input, you can create a method that will :
Go through the entire array and check if the string is in it (you can use equals() to check content of Strings)
Returns a boolean value wheter the string is in the array or not
Then just add a while structure to re-ask for an input
Basically it can look like this :
String input = "";
do {
input = keyboard.next();
}while(!checkString(input))
The checkString method will just go through all the array(using a for loop as you did to add elements) and returns the appropriate boolean value.
Without introducing some order in your array and without using an addition structure for instance HashSet, you will have to look through the whole array and compare the new item to each of the items already present in the array.
For me the best solution is to have a helper HashSet to check the item for presence.
Also have a look at this question.
To avoid you should use an Set instead of an array and loop until size = 10.
If you need to keep an array, you can use the .contains() method to check if the item is already present in the array.
while (no input or duplicated){
ask for a new string
if (not duplicated) {
store the string in the array
break;
}
}
You should check the input value in array before inserting into it. You can write a method like exists which accepts String[] & String as input parameter, and find the string into the String array, if it finds the result then return true else false.
public boolean exists(String[] strs, String search){
for(String str : strs){
if(str.equals(search))
return true;
}
return false;
}
performance would be O(n) as it searchs linearly.