I am trying to write a program that has the method public static void method(List<String> words) where the parameter words is a list of words from the text file words.txt that are sorted and contain only the words where each letter occurs only once. For example, the word "feel" would not be included in this list since "e" occurs more than once. The word list is not to be used as an argument in the rest of the program, so the method method is only to be used to store and remember the wordlist for later use. This function can also perform any of the sorting methods.
My thought process was to create a method that would read the text file, and use that text file as the argument in method. method would then filter out all words with letters that appear more than once, and also sort the new list.
When running the program, I'm getting an error "java.util.ConcurrentModificationException: null (in java.util.LinkedList$Listltr)" on the line for (String word : words). Also does the line public static List list; properly save and store the list for later use?
import java.util.*;
import java.io.*;
class ABC
{
public static List<String> list = new LinkedList<String>()
public static List readFile()
{
String content = new String();
File file = new File("words.txt");
LinkedList<String> words = new LinkedList<String>();
try
{
Scanner sc = new Scanner(new FileInputStream(file));
while (sc.hasNextLine())
{
content = sc.nextLine();
words.add(content);
}
}
catch (FileNotFoundException fnf)
{
fnf.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
System.out.println("\nProgram terminated safely");
}
for (String word : words)
{
if (letters(word) == false)
{
list.add(word);
}
}
Collections.sort(list);
return list;
}
public static boolean letters(String word)
{
for (int i = 0; i < word.length() - 1; i++)
{
if (word.contains(String.valueOf(word.charAt(i))) == true)
{
return true;
}
}
return false;
}
public static void main(String args[])
{
System.out.println(readFile());
}
}
The source of the error is that you are changing a list that you are iterating on. This is generally not a good idea.
Since you are building a new list, you don't actually need to change the one you are iterating on. I would recommend changing your code so that the logic for deciding if a letter appears more than once goes in a separate method. This way the complexity of any given method is manageable, and you can test them separately.
So create a new method that tests if any letter appears more than once:
static boolean doesAnyLetterAppearMoreThanOnce(String word) {
...
}
Then you can use it in your existing method:
for (String word : words) {
if (!doesAnyLetterAppearMoreThanOnce(word)) {
list.add(word);
}
}
Collections.sort(list);
Use an iterator. Try it like this.
Iterator<String> it = words.iterator();
while(it.hasNext()) {
CharSequence ch = it.next();
for (int j = 0; j < ch.length(); j++)
{
for (int k = j + 1; k < ch.length(); k++)
{
if (ch.charAt(j) == ch.charAt(k))
{
it.remove(word);
}
}
}
list.add(word);
}
However, I would approach it differently.
String[] data =
{ "hello", "bad", "bye", "computer", "feel", "glee" };
outer: for (String word : data) {
for (int i = 0; i < word.length() - 1; i++) {
if (word.charAt(i) == word.charAt(i + 1)) {
System.out.println("dropping '" + word + "'");
continue outer;
}
}
System.out.println("Keeping '" + word + "'");
List.add(word);
}
Note: You used feel as an example so it wasn't clear if you wanted to check for the same letter anywhere in the word or only adjacent letters that are the same.
There are several problems with you program:
public static List list;
Whenever you see a collection (like List) without a generics - it's a bad smell. Should be public static List<String> list;
Also consider changing public to private.
In readFile() method you mask the class variable 'list' with a local variable 'list'. So your class variable remains uninitialized:
list = new LinkedList<String>();
Better use try-with-resources for scanner:
try(Scanner sc = new Scanner(new FileInputStream(file))) {
You don't need to close it afterwards manually.
You cannot modify the list through which you are iterating. You should either use an iterator and its remove method, or create a new list and append good words to it, instead of removing bad words from the original list.
public static List<String> readFile() {
File file = new File("words.txt");
List<String> list = new ArrayList<>();
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String word = scanner.nextLine();
if (noDuplicates(word)) {
list.add(word);
}
}
Collections.sort(list);
} catch (FileNotFoundException e) {
System.out.println("File not found");
}
return list;
}
private static boolean noDuplicates(String word) {
Set<Character> distinctChars = new HashSet<>();
for (char c : word.toCharArray()) {
if (!distinctChars.add(c)) {
return false;
}
}
return true;
}
I suggest this shorter approach:
public static void method(List<String> words) {
words.removeIf(word -> {
Set<Integer> hs = new HashSet<>();
return word.chars().anyMatch(c -> {
if (hs.contains(c)) return true;
else hs.add(c);
return false;
});
});
System.out.println(words);}
words List now contain only the words where each letter occurs only once.
Related
I'm trying to search of multiple words given from a user ( i used array to store them in ) from one txt file , and then if that word presented once in the file it will be displayed and if it's not it won't.
also for the words itself , if it's duplicated it will search it once.
the problem now when i search for only one it worked , but with multiple words it keeps repeated that the word isn't present even if it's there.
i would like to know where should i put the for loop and what's the possible changes.
package search;
import java.io.*;
import java.util.Scanner;
public class Read {
public static void main(String[] args) throws IOException
{
Scanner sc = new Scanner(System.in);
String[] words=null;
FileReader fr = new FileReader("java.txt");
BufferedReader br = new BufferedReader(fr);
String s;
System.out.println("Enter the number of words:");
Integer n = sc.nextInt();
String wordsArray[] = new String[n];
System.out.println("Enter words:");
for(int i=0; i<n; i++)
{
wordsArray[i]=sc.next();
}
for (int i = 0; i <n; i++) {
int count=0; //Intialize the word to zero
while((s=br.readLine())!=null) //Reading Content from the file
{
{
words=s.split(" "); //Split the word using space
for (String word : words)
{
if (word.equals(wordsArray[i])) //Search for the given word
{
count++; //If Present increase the count by one
}
}
if(count == 1)
{
System.out.println(wordsArray[i] + " is unique in file ");
}
else if (count == 0)
{
System.out.println("The given word is not present in the file");
}
else
{
System.out.println("The given word is present in the file more than 1 time");
}
}
}
}
fr.close();
}
}
The code which you wrote is error prone and remember always there should be proper break condition when you use while loop.
Try the following code:
public class Read {
public static void main(String[] args)
{
// Declaring the String
String paragraph = "These words can be searched";
// Declaring a HashMap of <String, Integer>
Map<String, Integer> hashMap = new HashMap<>();
// Splitting the words of string
// and storing them in the array.
String[] words = new String[]{"These", "can", "searched"};
for (String word : words) {
// Asking whether the HashMap contains the
// key or not. Will return null if not.
Integer integer = hashMap.get(word);
if (integer == null)
// Storing the word as key and its
// occurrence as value in the HashMap.
hashMap.put(word, 1);
else {
// Incrementing the value if the word
// is already present in the HashMap.
hashMap.put(word, integer + 1);
}
}
System.out.println(hashMap);
}
}
I've tried by hard coding the values, you can take words and paragraph from the file and console.
The 'proper' class to use for extracting words from text is java.text.BreakIterator
You can try the following (reading line-wise in case of large files)
import java.text.BreakIterator;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class WordFinder {
public static void main(String[] args) {
try {
if (args.length < 2) {
WordFinder.usage();
System.exit(1);
}
ArrayList<String> argv = new ArrayList<>(Arrays.asList(args));
String path = argv.remove(0);
List<String> found = WordFinder.findWords(Files.lines(Paths.get(path)), argv);
System.out.printf("Found the following word(s) in file at %s%n", path);
System.out.println(found);
} catch (Throwable t) {
t.printStackTrace();
}
}
public static List<String> findWords(Stream<String> lines, ArrayList<String> searchWords) {
List<String> result = new ArrayList<>();
BreakIterator boundary = BreakIterator.getWordInstance();
lines.forEach(line -> {
boundary.setText(line);
int start = boundary.first();
for (int end = boundary.next(); end != BreakIterator.DONE; start = end, end = boundary.next()) {
String candidate = line.substring(start, end);
if (searchWords.contains(candidate)) {
result.add(candidate);
searchWords.remove(candidate);
}
}
});
return result;
}
private static void usage() {
System.err.println("Usage: java WordFinder <Path to input file> <Word 1> [<Word 2> <Word 3>...]");
}
}
Sample run:
goose#t410:/tmp$ echo 'the quick brown fox jumps over the lazy dog' >quick.txt
goose#t410:/tmp$ java WordFinder quick.txt dog goose the did quick over
Found the following word(s) in file at quick.txt
[the, quick, over, dog]
goose#t410:/tmp$
To take an arraylist of strings consisting of strings like:
fewf5677
kskfj654
pqoen444
mgnwo888
And i want to split them up BUT i DON'T want to use the split method because I have to perform other calculations with the letters that i'have split up.
SO i'have decided to use the subList method. But I can't seem to find a proper example of implementing this correctly. Take a look at my code. Below is a method that takes in an arraylist of strings as the parameter:
public static void splitup(ArrayList<String> mystrings){
mystrings.subList(String[] letters, double numbers);
}
So overall, how do I take each string of letters and numbers and store them into their own string arrays? For example, i want
fewf
kskfj
pqoen
mgnwo
to be in their own string along with
5677
654
444
888
to be their own numbers.
You could use regex as seen in this answer and then check for a pattern as shown in this answer as follows:
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringSplitter {
public static void main(String[] args) {
ArrayList<String> myStringsList = new ArrayList<String>();
ArrayList<String> stringsList = new ArrayList<String>();
ArrayList<String> numbersList = new ArrayList<String>();
myStringsList.add("fewf5677");
myStringsList.add("kskfj654");
myStringsList.add("pqoen444");
myStringsList.add("mgnwo888");
for (String s : myStringsList) {
String splittedString[] = s.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
for (String string : splittedString) {
Matcher match = Pattern.compile("[0-9]").matcher(string);
if (match.find()) {
numbersList.add(string);
} else {
stringsList.add(string);
}
}
}
for (String s : numbersList) {
System.out.println(s);
}
for (String s : stringsList) {
System.out.println(s);
}
}
}
This will output:
5677
654
444
888
fewf
kskfj
pqoen
mgnwo
Remember that split() takes a regex as parameter, not a String and so, you can do something like the above code to get the desired output.
What you are trying to do is a bit strange. Why are you trying to overload subList method?
One of possible examples of what you could do is to iterate over mystrings list and separate each string into two variables.
http://crunchify.com/how-to-iterate-through-java-list-4-way-to-iterate-through-loop/
If you are familiar with regular expressions you can use them them.
If not you can iterate over string characters to separate letters from number.
http://java11s.blogspot.com/2012/02/java-program-to-separate-alphabets-and.html
Then add result to two separate lists List<String> and List<Double> (or probably List<Integers>) or create custom data structure.
You can try this way :
If we consider that the format of your input is a String in which you want to extract integers, then you should to test one element by one:
Main
public static void main(String[] a) {
List<String> myList = new ArrayList<>();
myList.add("fewf5677");
myList.add("kskfj654");
myList.add("pqoen444");
myList.add("mgnwo888");
List<String> listStrings = new ArrayList<>();
List<Integer> listIntegers = new ArrayList<>();
for (int i = 0; i < myList.size(); i++) {
listStrings.add(getStringPart(myList.get(i)));
listIntegers.add(Integer.parseInt(getIntegerPart(myList.get(i))));
}
System.out.println(listStrings);
System.out.println(listIntegers);
}
Get the string part of your element
private static String getStringPart(String str) {
String s = "";
for (int i = 0; i < str.length(); i++) {
if (!testInteger(str.charAt(i))) {
s += str.charAt(i);
} else {
break;
}
}
return s;
}
Get the Integer part of your element
private static String getIntegerPart(String str) {
String s = "";
for (int i = 0; i < str.length(); i++) {
if (testInteger(str.charAt(i))) {
s += str.charAt(i);
}
}
return s;
}
A method to check if your str is and Integer or not
private static boolean testInteger(char str) {
try {
Integer.parseInt(str+"");
return true;
} catch (Exception e) {
return false;
}
}
Output
[fewf, kskfj, pqoen, mgnwo]
[5677, 654, 444, 888]
Hope this can help you.
I have an assignment where I have to create 3 classes Oblig6(main method), Word(Ord) and Wordlist(Ordliste). I have to find the number of times a word is repeated in a text using the word class.
I have a problem formulating the following segment. I need the word class to make a new object of the given word if it's already in the wordlist(ArrayLis ordliste), and then next time it finds the same word in the text, it has to add 1 to the total amount for that specific object defined by Ord(String s). I know that i'm creating a new object every time it finds a word that is in the wordlist, i need a suggestion on how to formulate it correctly.
Here is my code.
The wordlist class, the main problem is in void fraOrdtilOrdliste.
import java.util.Scanner;
import java.io.File;
import java.util.ArrayList;
public class Ordliste {
private ArrayList<String> ord = new ArrayList<String>();
private ArrayList<String> ordliste = new ArrayList<String>();
private int i = 0;
private int totalord = 0;
private int antallforekomster = 0;
// Reads the provided txt file and puts the words into a word list
void lesBok(String filnavn) throws Exception {
File file = new File(filnavn);
Scanner innlestfil = new Scanner(file);
while (innlestfil.hasNextLine()) {
ord.add(innlestfil.nextLine());
}
}
// Reads ord arryalist and compares the words to ordliste arraylist, adds them if they are not inn it all ready
//If they are there, crates a new Ord(String s)object of that words and adds to amount.
void fraOrdtilOrdliste () {
ordliste.add(ord.get(i));
for (i=0;i<ord.size();i++) {
Boolean unik = true;
for (int j = 0; j<ordliste.size();j++) {
if (ordliste.get(j).equalsIgnoreCase(ord.get(i))) {
unik = false;
new Ord(ordliste.get(j)).oekAntall();
}
}
if (unik) {
ordliste.add(ord.get(i));
}
}
}
// Using the Ord class as a counter for this method. If the word is registerd beforhand it will add 1.
void leggTilOrd(String s) {
for (i = 0; i < ord.size(); i++) {
if (ord.get(i).equalsIgnoreCase(s)) {
ord.add(i, s);
System.out.println("Suksess");
} else if (!ord.get(i).equalsIgnoreCase(s)) {
new Ord(s).oekAntall();
System.out.println("Antall okt");
return;
}
}
}
// Searches for the word in the wordlist and returns null if it does not exist.
Ord finnOrd(String s) {
for (i = 0; i < ord.size(); i++) {
if (!s.equalsIgnoreCase(ord.get(i))) {
System.out.println("null");
return null;
} else if (s.equalsIgnoreCase(ord.get(i))) {
System.out.println("Fant ordet");
}
}
return null;
}
// Prints out the total amount of words in the word list.
int antallOrd() {
for (i = 0; i < ordliste.size(); i++) {
totalord++;
}
System.out.println("Antall ord i ordlisten er: " + totalord);
return totalord;
}
// Counts the total amounts of a word in the word list.
int antallForekomster(String s){
antallforekomster= new Ord(s).hentAntall();
System.out.println("Ordet forekommer " + antallforekomster + " ganger");
return antallforekomster;
}
Hers is the word class.
ok, let me give it a shot, because i am not even sure i am reading your code correctly.
a) Define a class Word that has one member variable for the count and one member variable for the String word.
b) In your wordlist class have a member variable that is a List. Every time you parse a word out, loop through the List comparing the string you have with the string of the word. If matches, increment the count in the word class.
The loop sounds really ineffecient, but if you use a List then thats all you can really do. So your performance is basically O(nsquare) where n is the number of words in the text given.
WordList Class :
public class WordList {
static List<Word> words = new ArrayList<Word>();
public static void countWord(String inputWord) {
for (Word word : words) {
if (word.getWord().equals(inputWord)) {
word.setCount(word.getCount() + 1);
} else {
Word newWord = new Word();
newWord.setWord(inputWord);
newWord.setCount(1);
words.add(newWord);
}
}
}
}
Word Class :
public class Word {
String word;
int count;
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
What is the correct syntax for searching an ArrayList of strings for a single character? I want to check each string in the array for a single character.
Ultimately I want to perform multiple search and replaces on all strings in an array based on the presence of a single character in the string.
I have reviewed java-examples.com and java docs as well as several methods of searching ArrayLists. None of them do quite what I need.
P.S. Any pointers on using some sort of file library to perform multiple search and replaces would be great.
--- Edit ---
As per MightyPork's recommendations arraylist revised to use simple string type. This also made it compatible with hoosssein's solution which is included.
public void ArrayInput() {
String FileName; // set file variable
FileName = fileName.getText(); // get file name
ArrayList<String> fileContents = new ArrayList<String>(); // create arraylist
try {
BufferedReader reader = new BufferedReader(new FileReader(FileName)); // create reader
String line = null;
while ((line = reader.readLine()) != null) {
if(line.length() > 0) { // don't include blank lines
line = line.trim(); // remove whitespaces
fileContents.add(line); // add to array
}
}
for (String row : fileContents) {
System.out.println(row); // print array to cmd
}
String oldstr;
String newstr;
oldstr = "}";
newstr = "!!!!!";
for(int i = 0; i < fileContents.size(); i++) {
if(fileContents.contains(oldstr)) {
fileContents.set(i, fileContents.get(i).replace(oldstr, newstr));
}
}
for (String row : fileContents) {
System.out.println(row); // print array to cmd
}
// close file
}
catch (IOException ex) { // E.H. for try
JOptionPane.showMessageDialog(null, "File not found. Check name and directory.");
}
}
first you need to iterate the list and search for that character
string.contains("A");
for replacing the character you need to keep in mind that String is immutable and you must replace new string with old string in that list
so the code is like this
public void replace(ArrayList<String> toSearchIn,String oldstr, String newStr ){
for(int i=0;i<toSearchIn.size();i++){
if(toSearchIn.contains(oldstr)){
toSearchIn.set(i, toSearchIn.get(i).replace(oldstr, newStr));
}
}
}
For the search and replace you are better off using a dictionary, if you know that you will replace Hi with Hello. The first one is a simple search, here with the index and the string being returned in a Object[2], you will have to cast the result. It returns the first match, you were not clear on this.
public static Object[] findStringMatchingCharacter(List<String> list,
char character) {
if (list == null)
return null;
Object[] ret = new Object[2];
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.contains("" + character)) {
ret[0] = s;
ret[1] = i;
}
return ret;
}
return null;
}
public static void searchAndReplace(ArrayList<String> original,
Map<String, String> dictionary) {
if (original == null || dictionary == null)
return;
for (int i = 0; i < original.size(); i++) {
String s = original.get(i);
if (dictionary.get(s) != null)
original.set(i, dictionary.get(s));
}
}
You can try this, modify as needed:
public static ArrayList<String> findInString(String needle, List<String> haystack) {
ArrayList<String> found = new ArrayList<String>();
for(String s : haystack) {
if(s.contains(needle)) {
found.add(s);
}
}
return found;
}
(to search char, just do myChar+"" and you have string)
To add the find'n'replace functionality should now be fairly easy for you.
Here's a variant for searching String[]:
public static ArrayList<String[]> findInString(String needle, List<String[]> haystack) {
ArrayList<String[]> found = new ArrayList<String[]>();
for(String fileLines[] : haystack) {
for(String s : fileLines) {
if(s.contains(needle)) {
found.add(fileLines);
break;
}
}
}
return found;
}
You don't need to iterate over lines twice to do what you need. You can make replacement when iterating over file.
Java 8 solution
try (BufferedReader reader = Files.newBufferedReader(Paths.get("pom.xml"))) {
reader
.lines()
.filter(x -> x.length() > 0)
.map(x -> x.trim())
.map(x -> x.replace("a", "b"))
.forEach(System.out::println);
} catch (IOException e){
//handle exception
}
Another way by using iterator
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Naman");
list.add("Aman");
list.add("Nikhil");
list.add("Adarsh");
list.add("Shiva");
list.add("Namit");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next.startsWith("Na")) {
System.out.println(next);
}
}
}
I'm writing a program to delete duplicate consecutive words from a text file, then replaces that text file without the duplicates. I know that my current code does not handle the case where a duplicate word is at the end of one line, and at the beginning of the next line since I read each line into an ArrayList, find the duplicate, and remove it. After writing it though, I wasn't sure if this was an 'ok' way to do it since now I don't know how to write it back out. I'm not sure how I can keep track of the punctuation for beginning and end of line sentences, as well as the correct spacing, and when there are line returns in the original text file. Is there a way to handle those things (spacing, punctuation, etc) with what I have so far? Or, do I need to do a redesign? The other thing I thought I could do is return an array of what indices of words I need deleted, but then I wasn't sure if that's much better. Anyway, here is my code: (thanks in advance!)
/** Removes consecutive duplicate words from text files.
It accepts only one argument, that argument being a text file
or a directory. It finds all text files in the directory and
its subdirectories and moves duplicate words from those files
as well. It replaces the original file. */
import java.io.*;
import java.util.*;
public class RemoveDuplicates {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Program accepts one command-line argument. Exiting!");
System.exit(1);
}
File f = new File(args[0]);
if (!f.exists()) {
System.out.println("Does not exist!");
}
else if (f.isDirectory()) {
System.out.println("is directory");
}
else if (f.isFile()) {
System.out.println("is file");
String fileName = f.toString();
RemoveDuplicates dup = new RemoveDuplicates(f);
dup.showTextFile();
List<String> noDuplicates = dup.doDeleteDuplicates();
showTextFile(noDuplicates);
//writeOutputFile(fileName, noDuplicates);
}
else {
System.out.println("Shouldn't happen");
}
}
/** Reads in each line of the passed in .txt file into the lineOfWords array. */
public RemoveDuplicates(File fin) {
lineOfWords = new ArrayList<String>();
try {
BufferedReader in = new BufferedReader(new FileReader(fin));
for (String s = null; (s = in.readLine()) != null; ) {
lineOfWords.add(s);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public void showTextFile() {
for (String s : lineOfWords) {
System.out.println(s);
}
}
public static void showTextFile(List<String> list) {
for (String s : list) {
System.out.print(s);
}
}
public List<String> doDeleteDuplicates() {
List<String> noDup = new ArrayList<String>(); // List to be returned without duplicates
// go through each line and split each word into end string array
for (String s : lineOfWords) {
String endString[] = s.split("[\\s+\\p{Punct}]");
// add each word to the arraylist
for (String word : endString) {
noDup.add(word);
}
}
for (int i = 0; i < noDup.size() - 1; i++) {
if (noDup.get(i).toUpperCase().equals(noDup.get(i + 1).toUpperCase())) {
System.out.println("Removing: " + noDup.get(i+1));
noDup.remove(i + 1);
i--;
}
}
return noDup;
}
public static void writeOutputFile(String fileName, List<String> newData) {
try {
PrintWriter outputFile = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
for (String str : newData) {
outputFile.print(str + " ");
}
outputFile.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private List<String> lineOfWords;
}
An example.txt:
Hello hello this is a test test in order
order to see if it deletes duplicates Duplicates words.
How about something like this? In this case, I assume it is case insensitive.
Pattern p = Pattern.compile("(\\w+) \\1");
String line = "Hello hello this is a test test in order\norder to see if it deletes duplicates Duplicates words.";
Matcher m = p.matcher(line.toUpperCase());
StringBuilder sb = new StringBuilder(1000);
int idx = 0;
while (m.find()) {
sb.append(line.substring(idx, m.end(1)));
idx = m.end();
}
sb.append(line.substring(idx));
System.out.println(sb.toString());
Here's the output:-
Hello this a test in order
order to see if it deletes duplicates words.