This question already has an answer here:
Java: Find the index of a String in a list
(1 answer)
Closed 3 years ago.
I have an ArrayList of type Player and I am trying to search for a specific string and I'm having a lot of trouble.
Currently I'm using a boolean to see if the player contains the string. Then I use a for loop to search the list.
But it keeps outputting the final line of the file; I'm pretty sure im not searching properly.
String playerName = sc.next();
boolean isFound = players.contains(playerName);
int index = 0;
for (int i = 0; i < players.size(); i++) {
if (isFound) {
break;
}
index = i;
}
System.out.println(players.get(index));
System.out.println(isFound);
My Player class is defined as follows
(not sure if this helps)
public class Player extends Person {
public String pos;
public int g;
public int ab;
public int r; // various statistics for the player
public Player(String name, String team, String pos) {
this.name = name;
this.team = team;
this.pos = pos;
}
And i also have a league class containing the lists
public class League extends loadData {
public static ArrayList<Player> players = new ArrayList<Player>();
public static ArrayList<Pitcher> pitchers = new ArrayList<Pitcher>();
}
If anyone can help me out that would be much appreciated!
If you just need the index of an element in the list, use List#indexOf(). There is no need to check if the list contains the element first because if it does not, the method returns -1.
Example:
List<String> players = new ArrayList<String>
players.addAll(Arrays.asList("Jim, "Bob, "Mary");
int indexOfBob = players.indexOf("Bob");
If you plan on iterating through the list and performing an operation on all the elements until you reach a specific one, you don't need to use two index integers. Example:
int i;
for(i = 0; i < players.size(); i++) {
// Perform an operation on the current player.
if(players.get(i).equals("Bob")) break;
}
what's happening with your code
isFound is set only before loop. That's totally ok for checking if the string is contained within the list.
If the list doesn't contain the string, then the loop will never break and iterating through all elements. So in this case your index-counter i will point to the last element which then gets printed after the loop.
clarify type of list elements VS type of searched
If your list stores objects of Player you couldn't simply compare them to searched object String. Maybe you can — on each element of the list — compare for player.toString().contains(playerName) or you can check for player.getName().equalsIgnoreCase(playerName).
The type of you list's elements and it's declaration matter and need to be known (to us) in order to solve this.
solving search and print finding
assuming the list contains elements of type string, i.e. ArrayList<String> players
To check if an element (here string playerName) is contained you can use either (Array)List's indexOf or contains method.
Note: the string could be 0, 1, or multiple times contained in the list. The approaches above only find first or no occurrence.
For printing you can either print the search-term playerName directly if found. Or you can use the returned first found index of method-call index to get the matching element and print that.
Note: The text printed should be the same in both options, although instance-ids/hashCodes could vary.
Related
I'm trying to understand Array Object, and what I want to do is call my array in every class I have.
this is my code:
projectProva.java
public class ProjecteProva {
Scanner sc = new Scanner(System.in);
private final int maxContador = 4;
private final DadeArr LlistaUsuari[] = new DadeArr[maxContador];
int ContadorActual;
}
DadeArr.java
public class DadeArr {
private String nomUsuari;
private String cognomUsuari;
public DadeArr(String nU, String nC){
nomUsuari = nU;
cognomUsuari = nC;
}
Right now I'm working in projectProva.java , I have some method that saves into array a data input with scanner.
Here is an example of one of my method:
public int inserir(int aContadorActual){
ContadorActual = 1;
for (int i=1;i<=ContadorActual;++i){
System.out.println("Introdueix el nom del usuari: ");
String nU = sc.nextLine();
//sd.setNomUsuari(Name);
System.out.println("Introdueix el teu cognom : ");
String nI = sc.nextLine();
LlistaUsuari[ContadorActual] = new DadeArr(nU,nI);
System.out.println("El teu usuari s'ha creat satisfactoriament");
}
ContadorActual++;
return ContadorActual;
}
This method asks user his name and surname and saves it in array LlistaUsuari.
Then, I want to use this array(with the data in) in another .java file from the same package, but i don't know how to properly call the array.
I just started to learn this type of array, and i want to understand it.
After solving this , im looking forward to take all array info and send it to a data base or text file.
If I can't proceed with it i will switch to Array 2D.
Plus, I'm wondering if this type of Array ( array object ) is very usefull or not.
Thanks.
I also made this question at https://www.reddit.com/r/javahelp/comments/dsyu4b/array_object/?
You have multiple gotchas in your code.
1. you should always iterate an array from index 0 (unless you have special needs or you are programming in a language like Python where arrays start from 0)
2. You should set the condition in the loop to be less than the exact length of the array. So in your case it will be i < LlistaUsuari.length. You are getting a null because you are only filling up index #1 of the array.
All you need is a public getter method for the array that you want to access.
Something like:
public DadeArr[] getLlistaUsuari() {
return this.LlistaUsuari;
}
And that should do it.
In other classes, create an instance of ProjecteProva (lets's call it pPI) and to get the array there, simply do pPI.getLlistaUsuari() and you'll have it,
I want to add a new element that has several arguments in an array. I know how to add with just one argument, but with more i don't know.
My code is:
private Calculate[] calculation;
public Element(int numElements) {
calculation = new Calculate[numElements];
}
public void addElement(Date elementDate, double price, ElementType type) {
int numElements = elements.length;
int i = 0;
if (i < numElements) {
Calculate[i] = calculation.elementDate;
Calculate[i] = calculation.price;
Calculate[i] = calculation.type;
i++;
}
}
Calculate[i] = calculation.elementDate;
Calculate[i] = calculation.price;
Calculate[i] = calculation.type;
You shouldn't assign to the same array index 3 times. You're overriding what you've just set.
Try this (Calculate should have a constructor):
Calculate[i] = new Calculate(elementDate, price, type);
You're also maintaining an index i, but you're not looping over anything. i is just incremented from from zero to one and is not really used (apart from an almost useless conditional check).
I suggest you read over a beginners Java tutorial. You seem to be missing a lot of the fundamentals, and Stack Overflow is not a place where we should have to show you how to write a for-loop. It's well-documented and demonstrated in a tonne of tutorials already.
I assume Calculate is a class defined else where with a constructor
There is a couple of issues in this piece of code:
You want to update the array, but specify array. Calculate[] is the array type. The name if the array is calculation. The other thing is that you are trying to access calculation.elementDate etc. but since that is an array, it does not have the field elementDate. I assume your Calculate class has that field. Also, you are not applying a loop. So currently your code will only update the array on index 0.
My code:
public void addElement(Date elementDate, double price, ElementType type) {
for(int i = 0; i < elements.length; i++) { // for loop over all elements in your array
Calculate calculate = new Calculate(elementDate, price, type) // I assume this constructor is available to initialize the Calculate object
calculation[i] = calculate;
}
Hope this helps.
I'm trying to make a booking system for a hotel using the MVC dp. I have a class with a fixed arraylist of rooms (from 1-25) inside the model and class in which I have the showAvailableRooms method in the controller package . I'm asking my View to print out the available rooms but the only thing it prints out is two square brackets ([]).
P.S. The get OccupiedRoom is another method I have in my bookinglist class (model). It checks if the dates you pass it as arguments are a problem to already existing bookings,if it is then it checks if the room is already in that occupied list and if it isn't it adds it to the list.
public void showAvailableRooms(MyDate arrivaldate, MyDate departuredate) {
ArrayList<Room> availablerooms = new ArrayList<Room>();
for (int i = 0; i < 25; i++) {
for (int j = 0; j < l.getOccupiedRoom(arrivaldate, departuredate).size(); j++) {
if (h.getRoom(i) != l.getOccupiedRoom(arrivaldate, departuredate).get(j)) {
availablerooms.add(h.getRoom(i));
} else if (l.getOccupiedRoom(arrivaldate, departuredate).size() == 0) {
System.out.println(h.getAllRooms());
}
}
System.out.println(availablerooms);
}
As i said in comment [] means your list is empty.
you add elements to availablerooms only in your inner loop, but if l.getOccupiedRoom returns you empty list, then code inside inner loop won't be executed, and no empty rooms will be added.
two square brackets ([]). Means that availablerooms doesn't have any entry. Either there are no available rooms, or it isn't getting populated correctly. Please check your logic.
I've got this constructor in the class Music:
protected String Title;
protected String Autor;
protected String Type;
protected int Code;
public Music (String title, String autor, String type, int code){
this.setTitle(title);
this.setAutor(autor);
this.setType(type);
this.setCode(code);
}
#Override
public String toString(){
return this.Title + " " + this.Autor + " " + this.Type + " " + this.Code;
}
Then, in other class called ManageMusic I create some methods to then use them on the main class. I also define a String array refered to the Music class which I will use in the main class:
private final Music[] musicList;
private int counter;
public ManageMusic(int maxSize) {
musicList= new Music[maxSize];
counter= 0;
public void add(Music m){
musicList[counter] = m;
counter++;
}
Here, I have to create a delete method which would delete a especific object from the musicList and return this list without that object.
This is the way I add music elements to the musicList on the main class:
static ManageMusic musiclist = new ManageMusic(20);
musicList.add(new Music(title, autor, format, code));
My approach for the delete method in the ManageMusic class is to copy this list into a new String[] and then copy it back to the list. But as I'm using an objet from Music instead of from String, I cannot make the copy back because it does not cast the String to the musicList:
public void delete(int code){
String[] newString = new String[musicList.length];
int index_1 = 0;
for (int i=0; i<musicList.length; i++){
if(i != code){
newString[index_1] = musicList[i].toString();
index_1++;
}
}
int index_2 = 0;
for (int i=0; i<newString.length; i++){ //THIS IS WHERE IT SAYS: Cannot convert
// from String to Music
musicList[index_2] = newString[i];
index_2++;
}
}
I have to do something not far from this, because then I've got a method that list elements from the musicList, so I cannot set a return statement for the method.
Why you can do it without an ArrayList
As some people suggested in the comments, you should probably use ArrayLists or similar stuff from the java.util.collection package.
However I assume you want to learn how such things work, so I will not provide you with code (First because I'm too lazy, second to encourage you to learn it yourself) but with some explanation.
edit: First: Your problem is that you copy strings, not references. Instead of trying to use the toString method, try to handle it with the "objects" (i.e. their references) themselves.
Error checking
As you might have noticed your add will cause an IndexOutOfBoundsException if you try to add another entry after your list reached your max_size. You should check for that. You should also check lots of things in the following explanations, I'll provide a few suggestions.
Simple deletion with your exact example
Just use Music[] instead of String[] and copy the reference of the temp Music[] to your musicList.
Better way to handle it: dynamic array structure
So what I suggest is to make use of a dynamic array structure. You will have to copy arrays around a lot, which can be a bit difficult. But basically it's what an ArrayList does.
Constructor
But how to implement that dynamic structure? Let's first start with the initialization, i.e. your constructor. You will not need a parameter for a maximum size (unless you want to restrict your music collection for some reason). Just create an array with size 0. (Of course you can also implement copy constructors and other things, but for the start keep it simple.)
add()
To add more music, you simply create a new array with the size of your current collection + 1, copy all references (this is probably the answer you were looking for. You take the strings, but just take the objects themselves) from the current array to the new array, add the new Music and change the reference of your member variable to your newly created, bigger array (i.e. assigning musicList = tempArray; or something similar). (Error checking: is the object null?)
delete()
For deletion you can do just the same. Create a new temporary array (this time with a reduced size), copy all values over but leave out the one you want to delete. To determine which shall be deleted you can either check for indices or even check the objects for equality. (Error checking: size of temp array should never be smaller than 1, so check if your array is empty - consider to use a method like isEmpty() for that.)
Why should I do this?
Once you got those concepts you will be able to manage your array in whatever way you like. Search through it, delete all elements, copy your music collection to your friend's, etc. etc.
And beyond that?
And after you learned this, go ahead and try the ArrayList - you will figure out it works very much like what you have just written. And now you can be proud that you not only can use ArrayLists, but also know how and why they behave like they do.
Its better to use ArrayList than writing own logic to delete object from existing array. Here is how you can use ArrayList :
{
ArrayList<Music> list = new ArrayList<Music>();
Music m1 = new Music(title, autor, format, code);
list.add(m1);
// similarly you can check whether object is present in ArrayList or not using
if(list.contains(m1)){ // This check whether object is present in ArrayList or not
//Do whatever you want
}
}
ArrayList example:
List<Music> musicList = new ArrayList<Music>();
adding to end of list list:
musicList.add(new Music(...));
adding to specified position in list (later ones all move up one place)
musicList.add(index, new Music(..));
remove from list:
musicList.remove(index);
or
musicList.remove(someMusic);
Size of list:
int size = musicList.size();
Get first music:
Music first = musicList.get(0);
Get last music:
Music last = musicList.get(musicList.size()-1);
Loop:
for (Music : musicList) {
//do stuff
}
do like this
public void delete(int code){
List<Music> list = new ArrayList<Music>(); //creating new empty list
for (Music m:musicList){
if(m.code != code){ // removing condition
list.add(m); // adding music to new list
}
}
musicList = list.toArray(new Music[list.size()]); // assigning back list to musicList
}
How can I implement binary search to find a string with a particular prefix in generic array (which in this case will be a string[]). I tried compareTo but that wouldn't help because i have to use a string prefix. eg String prefix "Bi" bill, bilards ...etc..
Implement the following method to return all strings in an alphabetically sorted array that start with a given prefix. For instance, given a prefix “bi”, the returned strings are ”Bill Clinton”, ”Bill Gates”, and ”Bill Joy”. Note that all string comparisons should be case INSENSITIVE. The strings in the returned list must be in the order in which they appear in the array. Your implementation must be based on binary search, and must run in worst case O(log n+k) time, where n is the length of the array, and k is the number of matching strings. Assume that the array has no duplicate entries. If there are no matches, you may either return null, or an empty array list.
You may use the following String methods (in addition to any others you may recall):
boolean startsWith(String s)
int compareTo(String s)
int compareToIgnoreCase(String s)
String toLowerCase(String s)
String toUpperCase(String s)
(As for ArrayList, you only need to use the add method to add an item to the end of the array list.)
You may write helper methods (with full implementation) as necessary. You may not call any method that you have not implemented yourself
public static <T extends Comparable<T>> ArrayList prefixMatch(T[] list, String prefix) {
ArrayList<T> result = new ArrayList<T>();
int lo = 0;
int hi = list.length - 1;
while(lo <= hi) {
int mid = (hi + lo) / 2;
list[mid].startsWith(prefix) ? 0 : list[mid].compareTo((T) prefix));
}
return null;
}
You can use default binary search with custom comparator as your base, and then work our range by your self. I think the right algorithm would be:
Perform binary search on given array. Use comparator which checks only for prefix.
As result you'll get index of string which starts with your prefix
Walk to the left to find first string which matches prefix, remember position.
Walk to the right to find first string which matches prefix, remember position.
Copy elements from range start to range end from original array. That will be your desired array of all elements with prefix match condition.
Below is implementation in java. It works in happy case scenario but will crash if(I left those checks out to make code look simple):
No strings with given prefix exist in original array
There are string with length less then prefix length
Also if you need binary search implementation you could check source of Arrays.binarySearch
public class PrefixMatch {
public static void main(String[] args) {
final String[] prefixMathces = prefixMatch(new String[] { "Abc", "Abcd", "Qwerty", "Pre1", "Pre2", "Pre3", "Xyz", "Zzz" }, "pre");
for (int i = 0; i < prefixMathces.length; i++)
System.out.println(prefixMathces[i]);
}
public static String[] prefixMatch(final String[] array, final String prefix) {
final Comparator<String> PREFIX_COMPARATOR = new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.substring(0, prefix.length()).compareToIgnoreCase(o2);
}
};
final int randomIndex = Arrays.binarySearch(array, prefix, PREFIX_COMPARATOR);
int rangeStarts = randomIndex, rangeEnds = randomIndex;
while (rangeStarts > -1 && array[rangeStarts].toLowerCase().startsWith(prefix.toLowerCase()))
rangeStarts--;
while (rangeEnds < array.length && array[rangeEnds].toLowerCase().startsWith(prefix.toLowerCase()))
rangeEnds++;
return Arrays.copyOfRange(array, rangeStarts + 1, rangeEnds);
}
}
I assume that you currently have something like this? :
arrayElement.compareTo(prefix)
If so, you can change it to look like this:
arrayElement.startsWith(prefix) ? 0 : arrayElement.compareTo(prefix)
I suggest looking into the API code for this. There is an Arrays class that you can check out in the java.lang package and learn from there.
Working on a similar problem right now. I believe pseudo code will go something like yours. I created a pojo class Song. A song is made up up three strings artist,title, and lyrics.
When you create a song object you get :
// Artist Title Lyrics..
Song a = ["Farmer Brown", "Oh' Mcdonalad", "Oh'mcdonal had a farm eh i oh i oh"]
public class Song implements Comparable<Song> {
private String _artist;
private String _lyrics;
private String _title;
// constructor
public Song(String artist, String title, String lyrics) {
this._artist = artist;
this._title = title;
this._lyrics = lyrics;
}
public String getArtist() {
return _artist;
}
public String getLyrics() {
return _lyrics;
}
public String getTitle() {
return _title;
}
public String toString() {
String s = _artist + ", \"" + _title + "\"";
return s;
}
//This compare two song objects
public int compareTo(Song song) {
String currentSong = song.toString();
int x = currentSong.compareToIgnoreCase(this.toString());
return x;
}
This is your method here that will take in the array of songs and your prefix and use the compare method to see if they match. If they match the compareTo method returns a 0. If you get a 0 then you know you have found your song so return the arrayOfSongs[index where song is found].
I have not coded up my search yet but I modified yours to match my code. I have not tested it yet. I don't think you even need a compareTo method but you can use it. Also for scaling the binary search should return a list of songs that might match as you might have multiple songs that start with "xyz" . Kind of when you start searching on google with prefix "do" you get a drop down of "dog, donut,double" which gives the user something to choose like a search engine.
public static ArrayList<Song> search (String[] arrayOfSongs , String enteredPrefix) {
ArrayList<Song> listOfMatches = new ArrayList<Song>;
int mid;
int lo = 0;
int hi = arrayOfSongs.length - 1;
while(lo <= hi)
{
mid = (hi + lo) / 2;
if(arrayOfSongs[mid].startsWith(enteredPrefix))
{
System.out.println("Found a match, adding to list");
listOfMatches.add(arrayOfSongs[mid]);
}
}
return listOfMatches;
}
Once you have a listOfMatches of possible suspects of the song you want you can use the compareTo method in some way.