I have a program that has a list of items.
I then search for a string and try to find it in said list.
What I would want to happen is: It finds the first occurrence, then prints it out or saves it somewhere so I can use it later (by highlighting user choice for example). Then once I search for the same string again it should return me the second occurrence, then the third, etc. When it doesn't find any more occurrences it should go back to the start and repeat it.
This is a crude example of what I have:
public static void main(String[] args) {
ArrayList<String> exampleList = new ArrayList<String>();
exampleList.add("string1");
exampleList.add("john");
exampleList.add("string2");
exampleList.add("arnold");
exampleList.add("string3");
String inputExample = "str"
for (String s : exampleList) {
if (s.contains(inputExample)) {
System.out.println(s);
break;
}
}
}
I added the break inside the if so I can get only the first result. If I remove it I will get all results.
In the program I have similar code associated to the click of a button, highlighting the user choice if the list contains what the user searched for, this is just an example.
What happens in my program is that only the first result will be highlighted (because I broke out of the loop) or only the last result will be highlighted (because I didn't break out of the loop).
How can I make it so the search picks up where it left off, officially ignoring the results it already obtained?
As #Alex pointed out in his answer you should use an iterator and save your results in a private ArrayList for furthure use of those search results.
If you are not familiar with the iterator use this
I have written a simple class HighlightingUserInput that behaves as your conditions. It gives the first search result and prints it and saves in a ArrayList, if you didn't exit the program(or you can add a search button, if user presses search again) then gives the second search result, etc.
Feel free to ask anything related to this following program.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
public class HighlightingUserInput{
private static ArrayList<String> resultsString=new ArrayList<>();
public static void main(String [] args) {
ArrayList<String > allStrings=new ArrayList<>();
allStrings.add("string1");
allStrings.add("john");
allStrings.add("string2");
allStrings.add("arnold");
allStrings.add("string3");
Scanner scanner=new Scanner(System.in);
CharSequence userIput=scanner.nextLine();
Iterator iterator = allStrings.iterator();
while(!scanner.nextLine().equals("exit")) {
inner:
while (iterator.hasNext()) {
String s = (String) iterator.next();
if (s.contains(userIput)) {
System.out.println(s);
HighlightingUserInput.resultsString.add(s);
break inner;
}
}
if(!iterator.hasNext())
iterator = allStrings.iterator();
}
}
}
You can loop through your list and each time you find the string you can call your method to highlight it. Alternatively, if you want to be able to get strings 1 by 1 each time you call your method, then you can use an iterator. On the first call to your method you obtain an iterator for your list and store it in a private field of your class. On subsequent calls you use this iterator to get the next matching string from your list.
public static void main(String[] args) {
ArrayList<String> exampleList = new ArrayList<String>();
exampleList.add("string1");
exampleList.add("john");
exampleList.add("string2");
exampleList.add("arnold");
exampleList.add("string3");
String inputExample = "str";
int count = 0;
while(count >= 0){
System.out.println(customSearch(exampleList, inputExample, count);
count ++;
} // write break statement when count reaches to a particular value based on your use case
String customSearch(List<String> words, String searchKey, int count){
List<String> searchedWords = words.stream().filter(word -> if word.toLowerCase().contains(searchKey.toLowerCase)).collect(Collectors.toList());
return searchWords.get(count%searchedWords.size());
Related
I implemented a queue using array. Now I want to remove a element by searching, if the element were there it must be removed from the queue.
public static void deleteFromQueue(PassengerQueue passengerQueue){
//passengerQueue.dequeue();
Scanner scan = new Scanner(System.in);
System.out.print("please Enter the Passenger name: ");
String name = scan.nextLine();
for (int i=0; i<passengerQueue.getPassenger().length; i++){
if (passengerQueue.getPassenger()[i].getName().equals(name)){
//
}
}
}
here my method of removing
Why do you specifically want to use an array. Please find an example attached using an ArrayList:
package stackoverflow;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Iterator;
public class QuickTest {
#Test
public void test() throws Exception {
PassengerQueue passengerQueue = new PassengerQueue();
passengerQueue.add(new Passenger("testName1"));
passengerQueue.add(new Passenger("testName2"));
Assertions.assertEquals(2, passengerQueue.size());
PassengerUtil.removeByName(passengerQueue, "testName1");
Assertions.assertEquals(passengerQueue.size(), 1);
System.out.println("All done");
}
private static class PassengerUtil {
/** #param passengerQueue Modified by reference. **/
private static void removeByName(PassengerQueue passengerQueue, String specifiedName) {
// Using an Iterator so that I don't trigger ConcurrentModificationException.
for (Iterator<Passenger> it = passengerQueue.iterator() ; it.hasNext() ; ) {
Passenger currPassenger = it.next();
if (currPassenger.getName().equals(specifiedName)) {
it.remove();
}
}
}
}
private class PassengerQueue extends ArrayList<Passenger> {
}
private class Passenger {
private String name;
public Passenger(String name) {
if (name == null) {
throw new NullPointerException("The " + Passenger.class.getSimpleName() + " cannot have a Name equal to NULL!");
}
this.name = name;
}
public String getName() {
return this.name;
}
}
}
Please note the following:
My PassengerQueue object extends ArrayList. So I have a type-safe list of Passengers just by extending ArrayList - I don't need to do anything else.
I use an Iterator to iterate over the list. Its a bit more verbose than your normal for-each loop, but its necessary to not trigger a ConcurrentModificationException. Java doesn't always like when you iterate over a list and then for example delete things from that list while you're iterating over it. (Maybe simple examples won't trigger the ConcurrentModificationException)
You called your list PassengerQueue. Please note that Java does have Queue(https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html) collections. Similar to me extending ArrayList you can look at Queue subclasses and extend that instead if you really need your Collection to function like a queue.
Your code, and mine, can currently delete multiple elements from the list if the list contains Passengers with the same name.
Your question title asked about deleting from an array using an index position. You can consider adding the Apache Commons Lang project to your classpath and using methods from their ArrayUtils
Actually, my answer can be improved to not even use an Iterator:
private static class PassengerUtil {
/** #param passengerQueue Modified by reference. **/
private static void removeByName(PassengerQueue passengerQueue, String specifiedName) {
passengerQueue.removeIf(currPassenger -> currPassenger.getName().equals(specifiedName));
}
}
Some reading on the latter code example here.
A 'Queue' is defined as a data structure that holds a sequence of items where you can only add something to the end (the 'tail') and where you can take something from the beginning, the 'head'. And sometimes it is said that you can get the current size of the sequence, ask whether the sequence is empty, and that you can look ('peek') at the first item without taking it.
That's the basics. And you can implement that in various ways.
There is an interface in Java (java.util.Queue) that provides the basic features described above. So when you declare
java.util.Queue myQueue = …
then you cannot search your queue for an item and remove it (ok, you can take all elements from your queue, one by one, and add again those you want to keep, but that's tedious).
But the implementation for java.util.Queue is java.util.LinkedList, and a list can be searched.
So you write
java.util.Queue myQueue = new java.util.LinkedList();
and as you now know that the implementation of your queue is in fact a list, you can write
…
for( var i = ((java.util.List) myQueue).iterator(); i.hasNext(); )
{
if( matchesCriteriaForRemoval( i.next() ) i.remove();
}
…
But this works only because you know some implementation details of myQueue – but that was what you want to hide when you chose to define it as java.util.Queue.
So when you have to be able to remove entries from your PassengerQueue, that data structure should provide a method to do so instead of revealing its internal implementation.
This means your code have to look like this:
public static void deleteFromQueue( PassengerQueue passengerQueue )
{
Scanner scan = new Scanner( System.in );
System.out.print( "please Enter the Passenger name: " );
String name = scan.nextLine();
passengerQueue.removeByName( name );
}
How this method PassengerQueue.removeByName() is implemented depends from the internal implementation of PassengerQueue; if it uses the java.util.List with the name passengers to store the passengers, it may look like this:
public final void removeByName( final String name )
{
for( var i = passengers.iterator(); i.hasNext(); )
{
if( passengerNameMatches( name, i.next() ) ) i.remove();
}
}
If you use another container for your passengers, that removal method has to be implemented differently …
Obviously I omitted all error handling, and the collections are generic types, but I used them as raw because of brevity.
I used TreeSet for this and it works in a per snapshot style. In other words, sort once displays once.
Now, I want to implement a realtime sorted table.
Whenever there is a value change in any elements, the sorted table will be updated accordingly.
To make the sorting work on a per update style, I tried to remove the element and add it to the TreeSet again.
quotes.remove(quote);
quotes.add(quote);
It doesn't work because I have to implement the sorting logic in compareTo() but it breaks the contract for identifying the object which makes the remove() work. TreeSet never call equals() and hashcode() as described in the Java Doc.
Any idea? Please advise.
code:
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String args[]) {
TreeSetTest test = new TreeSetTest();
test.onQuoteUpdate("appl", 1000d);
test.onQuoteUpdate("msft", 2000d);
test.onQuoteUpdate("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("msft", 5000d);
test.printTopStocks();
}
private Set<Quote> quotes = new TreeSet<Quote>();
public void onQuoteUpdate(String symbol, double turnover) {
final Quote quote = new Quote(symbol, turnover);
quotes.remove(quote);
quotes.add(quote);
}
public void printTopStocks() {
System.out.println("--Top Stocks By Turnover--");
for (final Quote quote : quotes) {
System.out.println(quote);
}
}
public static class Quote implements Comparable<Quote> {
private String symbol;
private double turnover;
public Quote(String symbol, double turnover) {
this.symbol = symbol;
this.turnover = turnover;
}
#Override
public int compareTo(Quote o) {
return Double.compare(o.turnover, turnover);
// return symbol.compareTo(o.symbol);
}
}
}
Update 1:
As proposed I tried this:
public static void main(String args[]) {
TreeMapTest test = new TreeMapTest();
test.onQuoteUpdate("appl", 1000d);
test.onQuoteUpdate("msft", 2000d);
test.onQuoteUpdate("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("face", 50d);
test.printTopStocks();
}
public int compareTo(Quote o) {
if(o.symbol.equals(symbol)) return 0;
return Double.compare(o.turnover, turnover);
}
The remove() return false which eventually there are four elements (expected 3) in the Set.
--Top Stocks By Turnover--
Quote [symbol=face, turnover=3000.0]
Quote [symbol=msft, turnover=2000.0]
Quote [symbol=appl, turnover=1000.0]
remove symbol face : false
add symbol face : true
--Top Stocks By Turnover--
Quote [symbol=face, turnover=3000.0]
Quote [symbol=msft, turnover=2000.0]
Quote [symbol=appl, turnover=1000.0]
Quote [symbol=face, turnover=50.0]
Update 2:
I tried PriorityQueue and here is the code:
https://code.sololearn.com/cb38Eo036c8y/#java
It doesn't work because PriorityQueue doesn't store elements in order. The ordering only works when you poll element from the Queue.
Update 3:
Tried user54321's suggestion that by using a custom collection(see below answer). However, it doesn't look good if there are two more elements having the same value of 'turnover'.
My requirement is a very ordinary one. It seems that none of a collection from JDK fits my case.
Update 4:
The solution from user54321 fits for my interim need.
https://code.sololearn.com/c14Ybab7AOFm/#java
Deleted my previously added answer. Looks like a wrong data structure is being used for the scenario.
Here is why.
When an item is being added or removed, TreeSet does a binary search through the available elements using compareTo().
In your case,
After adding first 3 elements, set looks like this.
[{appl, 1000d}, {msft, 2000d}, {face, 3000d}]
Now when you try to remove the element {face, 50d},
It starts searching at {msft, 2000d},
From compareTo() result it determines {face, 50d} should come before {msft, 2000d}.
And continues to search towards start of the elements ( checking with {appl, 1000d} next).
Since the search doesn't find {face, 3000d}, that element remains without being removed.
Next when you add the element {face,50}, similar search happens and since the search does not find {face, 3000},
It adds {face, 50} to the beginning.
Now the set looks like this.
[{face, 50}, {appl, 1000d}, {msft, 2000d}, {face, 3000d}]
Now the problem here is that compareTo() isn't capable of considering both symbol and turnover for a sensible sorting.
TreeSet can be used for getting a sorted collection of unique elements.
If you need to get a sorted collection of different objects with a particular sorting criteria, in this case turnover value, you can use a PriorityQueue
Update: Using a List and a Set in custom data structure
The problem here is that we have to maintain two conditions.
1. Symbol has to be unique
2. Collection should be sorted by turnover value
compareTo() in Quote can check one at a time and not both.
So in this case we may have to go for a custom data structure.
First use only turnover in compareTo();
#Override
public int compareTo(Quote o) {
return Double.compare(o.turnover, turnover);
}
Then implement the custom data structure.
Note that we are using a HashSet to keep track of the symbol alone.
Using a list so that duplicate turnover values can be kept.
static class QuoteCollection {
Set<String> symbols = new HashSet<>();
List<Quote> quotes = new LinkedList<>();
public void onQuoteUpdate(Quote q) {
if (symbols.contains(q.getSymbol())) {
// this requires quotes.equals() to be implemented
quotes.remove(q);
} else {
symbols.add(q.getSymbol());
}
insertToCollection(q);
}
// inserting at correct position to remain sorted
private void insertToCollection(Quote q) {
int index = Collections.binarySearch(quotes, q);
if (index < 0)
index = ~index; // bitwise compliment to find insert position if it is not available in the list
quotes.add(index, q);
}
public List<Quote> getQuotes() {
return quotes;
}
}
Then use it in the main(). Note that printTopStocks() has been changed a little.
public static void main(String args[]) {
Main test = new Main();
QuoteCollection quoteCollection = new QuoteCollection();
quoteCollection.onQuoteUpdate(new Quote("appl", 1000d));
quoteCollection.onQuoteUpdate(new Quote("msft", 2000d));
quoteCollection.onQuoteUpdate(new Quote("face", 3000d));
test.printTopStocks(quoteCollection.getQuotes());
quoteCollection.onQuoteUpdate(new Quote("face", 50d));
test.printTopStocks(quoteCollection.getQuotes());
}
public void printTopStocks(List<Quote> quotes) {
System.out.println("--Top Stocks By Turnover--");
for (final Quote quote : quotes) {
System.out.println(quote);
}
}
This approach does involve data duplication. However a sorted collection can be maintained at linear time complexity(since it uses 'List.remove()')
Couple of points :
Trying to remove elements even when you are adding it first time.
While updating you are trying to remove new element which does not exist in TreeSet. final Quote quote = new Quote(symbol, turnover); here you are building new element which is Quote("face","50d") which does not exist when you are calling quotes.remove(quote);
Below is the one of the way to solve it, I am hard coding oldQuote to keep it short but you can update it:
public void onAdd(String symbol, double turnover) {
final Quote quote = new Quote(symbol, turnover);
quotes.remove(quote);
quotes.add(quote);
}
public void onQuoteUpdate(String symbol, double turnover) {
final Quote newQuote = new Quote(symbol, turnover);
final Quote oldQuote = new Quote("face", 3000d);
quotes.remove(oldQuote);
quotes.add(quote);
}
public static void main(String args[]) {
TreeSetTest test = new TreeSetTest();
test.onAdd("appl", 1000d);
test.onAdd("msft", 2000d);
test.onAdd("face", 3000d);
test.printTopStocks();
test.onQuoteUpdate("face", 50d);
test.printTopStocks();
}
I have a class Container where a user should be able to input any number of words until he types nothing. I have addWord(Word) method where each input is added to an ArrayList words every time do/while loop is run. I am passing user input value as a parameter to addWord() method each time loop runs.
Now I want to to display all elements of an array using display() method once the do/While loop has stopped running. But for some reason when i try to call method display(), it just shows an empty array [].
Is there any way you can help?
import java.util.ArrayList;
import java.util.List;
public class Container {
private List<String> words;
public Container() {
}
public List<String> getWords() {
return words;
}
public void setWords(List<String> words) {
this.words = words;
}
public void addWord(String word) {
words = new ArrayList<String>();
words.add(word);
}
public void display() {
System.out.println(words);
}
}
Main method:
import java.util.Scanner;
public class ContainerMain
{
public static void main(String[] args)
{
Container one = new Container();
Scanner myScan = new Scanner(System.in);
String word = "s";
do
{
word = myScan.nextLine();
one.addWord(word);
}
while (!word.equals(""));
if (word.equals("")) {
one.display();
}
else {
System.out.println("No hope fam");
}
}
}
Look at your addWord method:
public void addWord(String word) {
words = new ArrayList<String>();
words.add(word);
}
Each time you call that, it's going to create a new list - so you can never end up with more than one word in it.
The first line, initializing words, should be in your constructor (or as a field initializer). Then remove the line from addWord - ideally making the words field final at the same time, to avoid mistakes like this in the future, and remove the setWords method unless you really need it for something else.
That's all that wrong in Container (although it's not clear that it's really providing any value beyond just using a List<String> directly). As noted in comments, currently your do/while loop in main will add an empty string at the end. Also, there's no point in checking whether word is empty or not after the loop - it has to be, otherwise you wouldn't have exited the loop!
I found an exercise in a book that adds some money into an ArrayList, and then reverses them. I know we can easily use Collection.reverse(), which is what my textbook shows, but I found another cool solution online that I am trying to understand but having trouble with.
Heres the code:
class Purse {
private ArrayList<String> coins = new ArrayList<String>();
public void addCoin(String coinName) {
coins.add(coinName);
}
public void reverse() {
for(int start = 0, end = coins.size() - 1; start < coins.size() / 2; start++, end--) {
swap(start,end,coins);
}
}
private void swap(int starting, int ending, List aList) {
Object temp = aList.set(starting, aList.get(ending));
aList.set(ending,temp);
}
public String toString() {
return "Purse: " + coins;
}
}
public class PurseDemo {
public static void main(String [] args) {
Purse purseObj = new Purse();
purseObj.addCoin("Quarter");
purseObj.addCoin("Dime");
purseObj.addCoin("Penny");
purseObj.addCoin("Nickel");
System.out.println(purseObj);
purseObj.reverse();
System.out.println(purseObj);
}
}
Here is where my confusion is:
Object temp = aList.set(starting,aList.get(ending));
aList.set(ending,temp);
First of all, I think I get the idea of this. However, this is my first time seeing the Object keyword. What I don't really get is what temp actually represents ( I got this code off online, in my book they havent introduced this keyword Object yet)
Here are my thoughts on an example iteration
Suppose our arrayList has
[Quarter,Dime,Penny,Nickel]
According to Object temp = aList.set(starting,aList.get(ending));
We take the the first spot in the ArrayList Quarter and put the value of nickel in there. So we get the ArrayList
[Nickel,Dime,Penny,Nickel]
Now I'm kind of confused.. When I system.out.println(temp), it tells me the values are Quarter and Dime. But why? Can someone go through an example iteration with me?
AFTER READING ANSWER
[Quarter,Dime,Penny,Nickel]
Nickel replaces Quarter, thus temp is Quarter. So we add Quarter to the end
I.E we get
Quarter,Dime,Penny,Quarter
Wait.. But where did our nickel go?!
The set() method returns the object that is being displaced by the new object. The first line
Object temp = aList.set(starting,aList.get(ending));
is the same as:
Object temp = aList.get(starting);
aList.set(starting, aList.get(ending));
You could actually do it without the temp variable, in one line:
aList.set(ending, aList.set(starting, aList.get(ending)));
The swap method can be translated into its "usual form":
Object temp = aList.get(starting);
aList.set(starting, aList.get(ending));
aList.set(ending, temp);
All the code you found does is combine the first two lines because List.set promises to return the replaced value.
Now let's see your example, where aList initially is [Quarter,Dime,Penny,Nickel], and starting is 0 and ending is 3.
Object temp = aList.get(starting);, now temp is Quarter.
aList.set(starting, aList.get(ending));, now aList is [Nickel,Dime,Penny,Nickel].
At last, aList.set(ending, temp);, sets the last element of aList to Quarter: [Nickel,Dime,Penny,Quarter]
Edit
Many users are commenting that the Class Word is useless, which is probably true in this case. The reason I added it, is because I need it later on in the program.
This program has 3 classes - WordList, Word and a test class. I'm trying to get the method 'readBook' to read through a file, and send every word over to the method 'addWord'. Method addWord will check if the ArrayList allWords contains that word. If it doesn't, addWord will then add the word to an array, aswell as to send it over to class Word. When I run the program, nothing happens. I tried to print out allWords.size(), which returned 0.
Class WordList:
public class WordList {
String nextWord;
ArrayList<String> allWords = new ArrayList<String>();
public void readBook (String filename) throws Exception{
File file = new File(filename); //File has one word on each line.
Scanner innFile = new Scanner(file);
for (int i = 0; i<file.length(); i++){
if(innFile.hasNextLine()){
nextWord = innFile.nextLine();
addWord(nextWord);
}
}
}
private void addWord(String word){
for (String check : allWords){
if (!check.equalsIgnoreCase(word)){
allWords.add(word);
new Word(word);
}
else if(check.equalsIgnoreCase(word)){
System.out.println("The word allready exsist.");
}
else{
System.out.println("Something went wrong.");
}
}
}
Class Word:
public class Word {
String word;
ArrayList<String> allWords = new ArrayList<String>();
Word(String text){
word = text;
allWords.add(word);
System.out.print(allWords);
}
The test class:
public class TestClass {
public static void main (String[] args) throws Exception{
WordList list = new WordList();
list.readBook("path.../scarlet.text");
WordList newList = new WordList();
System.out.println(newList.numberOfWords());//A method printing out allWords.size()
}
}
You are populating allWords list of WordList class inside for (String check : allWords). Initially it would be empty hence it will never enter the for loop and allWords will never get populated. In turn new Word(word) will not be called and allWords of word class will be empty.
You have two issues with your code.
First, when that main loop (for (String check : allWords)) runs, allWords is going to be empty. Therefore, you will never add any elements to it, and that means it will always have a size of 0. To correct this, you probably need to add a boolean variable that gets set to true if you find the word. Then, after the loop, if the boolean variable is still false, add the word to the list.
Secondly, you've got allWords defined on two places: in your WordList class, and in your Word class. The WordList.allWords array is being updated correctly (as far as I can tell, once you fix the above mentioned issue). However, the Word.allWords array is not doing anything other than storing a single String value... twice (once in the array, once in a variable). The Word class isn't really doing anything useful, so I would opt to get rid of it.
I would get rid of the Word class completely, since it's currently not doing anything other than storing a String, which you could do with a String variable.
When the method addWord(String) is called it never enters the for loop because allWords is initially an empty ArrayList. Your call to "new Word(String)" is never reached.
I don't think you need allWords in both the Word class and the WordList class (?)
If you're just trying to get the unique words you can do this:
Set<String> words = new LinkedHashSet<>();
File file = new File("some file");
Scanner inFile = new Scanner(file);
for (int i = 0; i < file.length(); i++)
if (inFile.hasNextLine())
words.add(inFile.nextLine());
inFile.close();
then call
words.size()
to check if an array list contains a certain string you can use a for loop.
I'm not sure if this is the best way to go about it, but it should work.
for(int i = 0; i<yourArrayList.size(); i++){
if (yourArrayList.get(i).!contains(yourString)){
yourArrayList.add(yourString);
}
In test class try:
public static void main(String[] agrs) throws Exception {
WordList w = new WordList();
w.readBook("pathToMyFile"); // This way you access to readBook method
....
}
And add the word in method addWord when attribute allWords is empty.
private void addWord(String word){
if (allWords.isEmpty()) {
allWords.add(word);
} else {
// Your code
}
}