I'm familiar with the ways I can get an element position in array, especially the ones showed here: Element position in array
But my problem is I can't figure out how to convert this code to fit my needs.
What I want to check is if a String has a match in an ArrayList and if so, what's the index of the String in the ArrayList.
The annoying part is I managed to verify the String is in the ArrayList (see first line of my code)
listPackages is the ArrayList
current_package is the String I want to find its position in listPackages.
Here's my code:
if (listPackages.contains(current_package)) {
int position = -1;
for(int j = 0; j < listPackages.size(); j++) {
if(listPackages[j] == current_package) {
position = j;
break;
}
}
}
Would appreciate any help!
Thanks!
Use indexOf:
int index = listPackages.indexOf(current_package);
Note that you shouldn't generally use == to compare strings - that will compare references, i.e. whether the two values are references to the same object, rather than to equal strings. Instead, you should call equals(). That's probably what was going wrong with your existing code, but obviously using indexOf is a lot simpler.
just use the call listPackages.indexOf(current_package);
ArrayList.contains(Object o) calls indexOf(Object o) internally in ArrayList:
/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* #param o element whose presence in this list is to be tested
* #return <tt>true</tt> if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
Hope this will help you.change your code like this:
if (listPackages.contains(current_package)){
int position=listPackages.indexOf(current_package);
}
Also if you will make position variable as global you can access its value outside this block of code. :)
use the indexof method to get the position -
listPackages.indexOf(current_package)
http://download.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html#indexOf(java.lang.Object)
Related
The following is the source code for Conlletion.contains(Object o) in ArrayList:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
I want to know why not type check first,for example:
public boolean contains(Object o) {
if(o.getClass() != elementData[0].getClass())
return false;
return indexOf(o) >= 0;
}
This is more efficient when o is a different type,isn't it?
(ps:Sorry, my English is not very good, I don't know if I speak clearly)
Since elementData is always allocated as an Object[], the expression elementData.getClass().getComponentType() is the same as Object.class, so if (o.getClass() != elementData.getClass().getComponentType()) would pretty such always be true, i.e. contains() would pretty such always return false.
Your suggestion wouldn't work, that's why it's not done that way.
Besides, even if you could, it still wouldn't work, because the values of a Collection object can be any subclass of the type specified for the collection.
E.g. an ArrayList<Number> can contain a mix of Integer, Long, Double, ... objects, so even if elementData.getClass().getComponentType() would have returned Number.class, it would still be a bad type check.
I am only guessing but I think it was an api design decision.
Since Java supports overwriting the equals method- it is up to the programmer to decide what it means for two objects to be equal. In theory, two objects of different types can be considered equal in a certain domain. It is true that checking for type equality is common when implementing equals, but it is not a mandatory. Since contains is a method for the most general case, no assumptions were made regarding the domain it would be called in.
I have below code and I have placed break points on overridden equals() and hashCode() methods of ContainerBean. When I run below application in debug mode, debugger stops at hashCode() only for System.out.println line and not while trying to remove element from List.
import java.util.ArrayList;
import java.util.List;
public class ListRemovalDriver {
public static void main(String[] args) {
List<ContainerBean> remitClaims = new ArrayList<>();
ContainedBean addedRemit1 = new ContainedBean();
addedRemit1.setRemitId(12345L);
ContainerBean added1 = new ContainerBean();
added1.setRemitBean(addedRemit1);
remitClaims.add(added1);
ContainedBean removedRemit1 = new ContainedBean ();
removedRemit1.setRemitId(12345L);
ContainerBean removed1 = new ContainerBean ();
removed1.setRemitBean(removedRemit1);
System.out.println("List before valid removal" + remitClaims);
remitClaims.remove(removed1);
System.out.println("List after valid removal" + remitClaims);
}
}
Am I missing something?
Would overridden equals() in ContainerBean not be called while removing element from list?
EDIT
I forgot to mention that hashCode() and equals() are working as expected i.e. elements getting removed as per equals() logic but its only debugger that is not taking me there on list remove function call.
Since you did not give the code I have to guess: You did not override equals, but instead added an overload like this:
public boolean equals(ContainerBean c) { ... }
This will not work because equals(Object) is called.
Change your equals implementation to take an argument of type Object and it will both get called and stopped at in eclipse debugger.
Would overridden equals() in ContainerBean not be called while
removing element from list ?
Yes, when you are using remove(Object o), then equals() in ContainerBean will be called to check the equality of the object and then remove it from the list as mentioned in the ArrayListAPI below (emphasis mine):
Removes the first occurrence of the specified element from this list,
if it is present. If the list does not contain the element, it is
unchanged. More formally, removes the element with the lowest index i
such that (o==null ? get(i)==null : o.equals(get(i))) (if such an
element exists). Returns true if this list contained the specified
element (or equivalently, if this list changed as a result of the
call).
But, on the other side, when you are removing an element using the index of the list (i.e., using remove(int index)), then there will NOT be any equals() check.
You can look here
Source code of ArrayList from jdk 7,
ArrayList.remove(Object o)
it invokes equals method to verify the object to remove from the collection
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
source: ArrayList Source
I was wondering how the method indexOf of an ArrayList is implemented. In fact I have override the equals method like this:
public class CustomObject {
#Override
public boolean equals(Object o) {
if(o instanceof CityLoader)
return ((CityLoader)o).getName() == this.name;
else if (o instanceof String)
return this.name.equals((String)o);
return false;
}
}
I though this will avoid me to override also the indexOf method but it seems I am totally wrong.
When I try
ArrayList<CustomObject> customObjects = new ArrayList<CustomObject>
... insert customobject into the arraylist ...
customObjects.indexOf(new String("name"))
indexOf return false but it should return true. (I checked the element I am looking for exists)
Am I totally wrong?
equals should never return true when the compared objects are not of the same type (in your case CustomObject's equals should always return false when o is not an instance of CustomObject).
The implementation of indexOf happens to use String's equals instead of your CustomObject's equals when you pass a String to it, and String's equals returns false when you pass to it a object that is not a String.
In addition, don't use == in comparison of Strings.
You should pass an instance of CustomObject to indexOf :
customObjects.indexOf(new CustomObject("name"))
(or whatever the constructor of CustomObject looks like)
Your equals method should look like this :
public boolean equals(Object o) {
if(!(o instanceof CityLoader))
return false;
CityLoader other = (CityLoader)o;
return other.name.equals(this.name);
}
customObjects.indexOf(new String("name"))
This is what you are doing wrong. You are looking for an index of a String inside a CustomObject object list.
From the java docs :
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* #param o element to search for
* #return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
* #throws ClassCastException if the type of the specified element
* is incompatible with this list
* (optional)
* #throws NullPointerException if the specified element is null and this
* list does not permit null elements
* (optional)
*/
int indexOf(Object o);
I'm not to sure on how to explain this but basically I am trying to refer to the List Classes front which is of Element A(can be from any list). But what happens is that when it goes through the Elements of the list it is comparing from two different lists and ends up not matching. ie compares original list which contains the front b to list containing element A. Now I'm just wondering about how i would get the front of Element A set to b so that i can compare where it is.
/*front is a dummy element used to keep position.
List is a class i have made under requirements of naming for subject.
i don't want a solution. I only want to know about how to do it.
This is what is an example code of whats causing the problem USED IN DRIVER PROGRAM
DLL.concat(DLL2);
it is basically getting DLL's front and going through the loop when it should be using DLL2's.
DLL and DLL2 are both Lists
***/
//will return the index of the Element for comparing
private int checkElement(Element A){
Element b = front;
int i = 0;
while (b != a && i<size)
{
b = b.next;
i++;
}
return i;
}
//edit: add
//size is the size of the list gets increased everytime a variable is added to the list on top of the dummy element.
//Item is a private class inside the List class. it contains the values: element,next, previous in which element contains an object, next and previous contain the next element in the list and the previous one (its a double linked list)
// this is what causes the error to turn up in the above method as im using two different lists and joining them.
public void concat(List L){
if (splice(L.first(),L.last(),last())){
size = size+L.size;
}
}
//this is the splice method for cutting out elements and attaching them after t
//just using the check method to assert that a<b and will later use it to assert t not inbetween a and b
public boolean splice(Element a, Element b, Element t){
if (checkElement(a) < checkElement(b)){
Element A = a.previous;
Element B = b.next;
A.next = B;
B.previous = A;
Element T = t.next;
b.next = T;
a.previous = t;
t.next = a;
T.previous = b;
return true;
}
else {
System.out.println("Splicing did not occur due to b<a");
return false;
}
}
So despite my comment, I see one glaring problem with this. You can't use equality operators on reference types. That is, anything other than a primitive type (double, int, etc). What happens is you're comparing the address of the instance and unless they are literally the same object (same address in memory), it isn't going to return true, ever. Maybe that's what you want, but I suspect not. You need to override the method
public boolean equals(Object obj);
and use that to compare two instances of a given class. Am I correct in my assumptions?
Edit Ok, I think my original guess was correct. It works if they are from the same list because they end up being the same elements (stored in the same memory location). You need to use equals() or !equals() rather than == and !=. Try that, and see if it solves your problems. Also, don't just use them, you must override equals to actually compare the elements internal properties.
I have a problem with ArrayList. I'm using ArrayList like this:
private ArrayList<Playlist> mPlaylists;
where Playlist is a class inherited from another ArrayList.
I do the following:
p = new Playlist(...some parameters...);
mPlaylists.add(p);
Later, when I use 'p' to get the index in the list:
int index = mPlaylists.indexOf(p);
an index of '1' is returned, even though inspection of the list clearly shows that it's index '4'.
Does anybody know why this fails?
Thanks.
B.R.
Morten
Edit:
Same problem without indexOf(), using equals():
private int GetIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i).equals(playlist)) {
return i;
}
}
return -1;
}
New edit:
This WORKS!:
private int getIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i) == playlist) {
return i;
}
}
return -1;
}
Solution:
As suggested, I changed the Playlist class to not enherit from ArrayList, but rather keeping an instance privately. It turned out that I only had to implement 4 ArrayList methods.
This does the trick; Now indexOf() returns the correct object!
Thanks to all contributors!
Most likely your PlayList messed up with the default ArrayList equals implementation, because the way indexOf is calculated to something like:
indexOf(Object o)
if( o == null ) then iterate until null is found and return that index
if( o != null ) iterate until o.equals( array[i] ) is found and return taht index
else return -1
end
So, you are doing something funny with your .equals method or your are accidentally inserting another element in the list when you think it is at the end.
EDIT
As per your edit... see? Your .equals() method is broken.
Consider doing a good review and make sure it adheres to the description defined in Object.equals
From the API:
int indexOf(Object o):
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
So the answer is that you need to override .equals() in Playlist.
There may be many reasons for this behavior:
1) If multiple elements in an ArrayList are equal (according to equals method), then the first one is returned. Maybe you simply have multiple identical objects.
2) Your PlayList class extends ArrayList (I am not sure it's a good idea). Therefore, if you didn't override the equals method, the comparison is based on the sequence of elements only. For example, any two empty PlayList instances will be considered equal.
3) If you DID override equals, check your implementation. It must return true for a comparison with the same reference, and in your case it doesn't.
I'm not sure why you are having this problem, but I think if I were you I would choose to use the newer Generic List to create your list like this:
List<Playlist> mPlaylists = new List<Playlist>();
p = new Playlist(<some parameters>);
mPlaylists.Add(p);