Check if Object exists in ArrayList in Java - java

I have the following List of objects:
private List<Object> teamlist = new ArrayList<Object>();
And I'm adding objects to the list like so:
teamlist.add(new MCWarTeam(args[0], joinkey));
Now the objects in the list have no name, but can be referenced by using the list, right? Before I add a new element to the list, how can I check if an object with a certain attribute already exists? This is the constructor of the Objects:
public MCWarTeam(String teamname, String joinkey){
this.teamname = teamname;
this.joinkey = joinkey;
}
I want to check if there already is a team with the name teamname. Alternatively, is there a better way to store the Objects? Before, I just used a HashMap to add the teamname and joinkey and it worked just fine, but figured using Objects instead would be a better way to do it.
Here is the important code for the event handler:
else if (cmd.getName().equalsIgnoreCase("createTeam")) {
if (args.length > 0 && args.length < 3) {
String joinkey = "";
if (args.length > 1)
joinkey = args[1];
String teamname = args[0];
MCWarTeam newTeam = new MCWarTeam(teamname, joinkey);
if (!teamlist.containsKey(teamname)) {
teamlist.put(teamname, newTeam);
sender.sendMessage("Created new team \"" + teamname + "\" with join key \"" + joinkey + "\" successfully! Teams:");
sender.sendMessage("All teams:");
for (String key : teamlist.keySet()) {
sender.sendMessage(key);
}
} else
sender.sendMessage("Team already exists!");
return true;
}
return false;
}
else if (cmd.getName().equalsIgnoreCase("joinTeam")) {
if (args.length > 0 && args.length < 3) {
String joinkey = "";
if (args.length > 1)
joinkey = args[1];
String teamname = args[0];
if (teamlist.containsKey(teamname)) {
String teamKey = teamlist.get(teamname).getJoinKey();
if (joinkey == teamKey) {
teamlist.get(teamname).addPlayer(playername);
Bukkit.broadcastMessage("MCWar: " + playername + " joined Team \"" + teamname + "\" successfully!");
} else
sender.sendMessage("Join key incorrect!");
} else {
sender.sendMessage("Team doesn't exist! Teams:");
for (String key : teamlist.keySet()) {
sender.sendMessage(key);
}
}
return true;
}
return false;
}
Basically, if it returns false, the user will get a message explaining the correct usage of the command he entered.

Java's List<T> has a boolean contains(Object) method, which is handy for situations when you wish to avoid duplicates:
if (!teamlist.contains(newTeam)) {
teamlist.add(newTeam);
}
MCWarTeam class must implement equals in order for this to work. When you override equals, you must also override hashCode.
#Override
public boolean equals(Object obj) {
if (!(obj instanceof MCWarTeam)) {
return false;
}
MCWarTeam other = (MCWarTeam)obj;
return teamname.equals(other.teamname)
&& joinkey.equals(other.joinkey);
}
#Override
public int hashCode() {
return 31*teamname.hashCode()+joinkey.hashCode();
}
I'm just looking to check if an Object with the same teamname already exists, but not care about the joinkey?
If joinkey is not part of your object's state that influences equality, it is usually not a good idea to keep it as part of the object as a field. For example, if joinkey is something transient which you use to "connect" teams to other things, making a HashMap<String,MCWarTeam>, using joinkey as the key to the map, and removing joinkey from MCWarTeam should be a good idea.

Based on the description and your comments to other answers, it seems like a good idea to not use a List, but instead store your data in a Map<String, MCWarTeam>, which maps team names into MCWarTeam objects:
private Map<String, MCWarTeam> teams = new HashMap<>();
You can add a team, checking whether a team with the same name already exists, like this:
String teamName = args[0];
if (!teams.containsKey(teamName)) {
teams.put(teamName, new MCWarTeam(teamName, joinKey));
} else {
// do what you want when the team name was already in the map
}
Retrieving an MCWarTeam object based on team name, e.g. for accessing the joinKey attribute, is easy:
String joinKey = teams.get(teamName).getJoinKey();
Note that using this approach, you shouldn't implement equals or hashCode in MCWarTeam, because you aren't gonna need it; as your map keys are team names, containsKey operates on String objects which already have well-defined equals and hashCode semantics.

In order to search for an MCWarTeam instance in the ArrayList, you'll first have to override equals in order to define what it means for two MCWarTeam instances to be equal to each other. Then you can use indexOf(team) or contains to determine whether a instance is in the List.
However, such a search would take linear time, so a HashSet may be better for your needs (for that purpose you'll need to override both equals and hashCode, and you'll be able to find if an object is in the Set in constant time).

If you implement MCWarTeam equals method properly, then contains should tell you if the object exists.
boolean exists = teamlist.contains(member);
And as #Eran mentioned a HashSet would give you O(1) lookup where list contains is O(n), the only thing is that HashSet doesn't allow duplicates.
And Yes, use the actual type rather than Object
List<MCWarTeam> teamlist = new ArrayList<>();

Related

performace issue with the code ,exponential working

I have two lists of type object with data , the first one is principal entity and the second is dependent entity.
In addition I have key table that relate between the principal and depended entity objects.
In the first for statement I get one instance of type object and then I go and loop on every instance of the second entity and trying to find
Match between them (i think exponential problem…) ,if match is find update the principal entity with the reference object .
The following code is working but I check it from performance perspective and it's not working in efficient way.
Do you have an idea/tips how to improve this code from perforce aspect.
In the JVM monitor I found that EntityDataCreator.getInstanceValue have a problem.
This is the method start
// start with the principal entity
for (Object principalEntityInstance : principalEntityInstances) {
List<Object> genObject = null;
Object refObject = createRefObj(dependentMultiplicity);
// check entries in dependent entity
for (Object dependentEntityInstance : toEntityInstances) {
boolean matches = true;
for (String[] prop : propertiesMappings) {
// Get properties related keys
String fromProp = prop[0];
String toProp = prop[1];
Object fromValue = EntityDataCreator.getInstanceValue(fromProp, principalEntityInstance);
Object toValue = EntityDataCreator.getInstanceValue(toProp, dependentEntityInstance);
if (fromValue != null && toValue != null) {
if (!fromValue.equals(toValue)) {
matches = false;
break;
}
}
}
if (matches) {
// all properties match
if (refObject instanceof List) {
genObject = (List<Object>) refObject;
genObject.add(dependentEntityInstance);
refObject = genObject;
} else {
refObject = dependentEntityInstance;
break;
}
}
}
if (refObject != null) {
EntityDataCreator.createMemberValue(principalEntityInstance, navigationPropName, refObject);
}
}
public static Object getInstanceValue(String Property, Object EntityInstance) throws NoSuchFieldException,
IllegalAccessException {
Class<? extends Object> EntityObj = EntityInstance.getClass();
Field Field = EntityObj.getDeclaredField(Property);
Field.setAccessible(true);
Object Value = Field.get(EntityInstance);
Field.setAccessible(false);
return Value;
}
my guess would be your best bet is to go through both lists once, prepare all data that you need in hashtables, then do one iteration. this way, your problem becomes N+M instead of N*M
edit
Map<String,List<Object>> principalMap = new HashMap<String,List<Object>>();
for (Object principalEntityInstance : principalEntityInstances) {
List<String> keys = getKeysFor(principalEntityInstance);
for(String key : keys) {
List<Object> l = principalMap.get(key);
if(l==null) {
l = new ArrayList<Object>();
principalMap.put(key,l);
}
l.add(principalEntityInstance);
}
}
the do the same for dependentEntityInstance - this way, your searches will be much faster.
I might be misunderstanding your question, but I would suggest defining an equals method for your entities and a hashing method for them, so that you can leverage all the goodness that java already has for searching and matching entities already.
When at all possible rely on Java's infrastructure I think, Sun/Oracle spent a long time making it really fast.

Issues with Java HashMap and key Object I rolled myself

So, I'm trying to use a HashMap to map my own Object to a String value. My object is below (with some code removed for brevity)
public class RouteHeadsignPair {
String route;
String headsign;
public RouteHeadsignPair(String n_route, String n_headsign) {
route = n_route.toLowerCase();
headsign = n_headsign.toLowerCase();
}
public String getRoute () {
return route;
}
public String getHeadsign() {
return headsign;
}
public boolean equals(RouteHeadsignPair other) {
return(other.getRoute().equals(route) && other.getHeadsign().equals(headsign));
}
public int hashCode() {
return(route.hashCode());
}
}
I'm mapping a bunch of these objects to Strings by loading data from a text file. Later on, based on (independent) user input, I try to query the HashMap using a RouteHeadsignPair Object. containsKey() returns false and get() returns null, as if I had never added the key into the map. But, bizarrely, if I iterate over the map using the below code (where newKey is a RouteHeadsignPair made from user input)
RouteHeadsignPair foundKey = null;
Iterator<RouteHeadsignPair> keysInMap = routeHeadsignToStopIdMap.keySet().iterator();
while(keysInMap.hasNext()) {
RouteHeadsignPair currKey = keysInMap.next();
if(currKey.equals(newKey)) {
System.err.println("Did find a key with an equals() == true!");
foundKey = currKey;
}
}
System.err.println("Value in map? " + routeHeadsignToStopIdMap.containsKey(newKey) + "( hashcode = " + newKey.hashCode() +
", equals = " + newKey.equals(foundKey) + ")");
System.err.println("foundKey in map? " + routeHeadsignToStopIdMap.containsKey(foundKey) + "( hashcode = " + foundKey.hashCode() +
", equals = " + foundKey.equals(newKey) + ")" );
I apologize for the code formatting, it's late and I'm getting cranky
I get the following output
Did find a key with an equals() == true!
and then
Value in map? false( hashcode = 1695, equals = true)
foundKey in map? true( hashcode = 1695, equals = true)
So, if I iterate over the keys and look for keys that return equals(), I do find one, and the hashCode() is the same for both of these. If the hashCode() is the same for newKey and foundKey and foundKey.equals(newKey) returns true, shouldn't HashMap.get(key) return a value and containsKey() return true? What am I doing wrong here?
You're not overriding Object.equals - you're overloading it because of the parameter type. Your diagnostic code calls your overload, but the map code doesn't (as it doesn't know about it).
You need a method with a signature of
public boolean equals(Object other)
If you use the #Override annotation you'll get an error if you fail to override something properly.
You'll need to check whether other is an instance of RouteHeadSignPair first, then cast. If you make the RouteHeadSignPair class final, you won't need to worry about whether or not it's the exact same class, etc.
Note that your hash codes will collide unnecessarily, by the way - if you use both the route and the headSign hashes to generate your hash code, it may help your map lookups to be more efficient. (If there are several instances with the same route but different head signs, it's useful if the map doesn't have to check for equality on all of them when looking up a key.)

Using a for each loop to find two elements in an array list

I need help writing a for each loop which searches through an array list called peoplelist of type people. The loop needs to search for the values String postcode and String name in the array. It then needs to return their ID if it is found, and null if it is not. Any sort of help would be great!
If the class People is written like a Java bean (i.e. with standard getter methods), something like this would do the job:
for (People person : peopleList) {
if (person.getName().equals(name) && person.getPostcode().equals(postCode))
return person.getId();
}
return null;
If a person's name or postcode can be null, you may want to flip the equals calls to avoid null pointer exceptions (e.g. name.equals(person.getName()) instead of person.getName().equals(name)).
Btw Person would be a better name.
Need to make a lot of assumptions about your classes, but something like this should suffice:
for (People person : peoplelist) {
if (person.getPostCode().equals(postcode) && person.getName().equals(name)) {
return person.getId();
}
}
// deal with not being found here - throw exception perhaps?
With “two elements”, do you mean “two attributes of some class”? If so, something along these lines would do:
String id = null;
for(People p : peoplelist) {
if(somePostcode.equals(p.postcode) && someName.equals(p.name)) {
id = p.id;
break; // no need to continue iterating, since result has been found
}
}
// result “id” is still null if the person was not found
//In case multiple persons match :)
List<String> result = new LinkedList<String>();
for (People person : peopleList) {
if (person.getName().equals(name) && person.getPostcode().equals(postCode))
result.add(person.getId());
}
if(result.isEmpty()){
return null;
}else{
return result;
}
People foundPerson;
for (People eachPeople : peoplelist )
{
if (Integer.valueOf(eachPeople.getID()) == 10054
&& "Jimmy".equals(eachPeople.getName()))
{
foundPerson= eachPeople;
break;
}
}
Assuming you have a Person bean, then if you want to retrieve all instances of Person whose postcode and name match some values, you may do something like this:
public List<Person> searchFirst(List<Person> persons, String postcode, String name) {
List<Person> matchingPersons = new ArrayList<Person>();
for (Person person : persons) {
if (person.getPostcode().equals(postcode) && person.getName().equals(name))
matchingPersons.add(person);
}
return matchingPersons;
}
Next time, you may want to show us your code, so we can help you in understanding what you're doing wrong :)

Duplicates in Arraylist, comparing various fields java

I have a code to return an arrayList with the duplicates of an ArrayList
but seems it's not working, I am comparing all items in the array...
public ArrayList<ObjectList> duplicates(ArrayList<ObjectList> someObjectsList) {
ArrayList<ObjectList> ret = new ArrayList<ObjectList>();
for ( ObjectList aSomeObjectsList: someObjectsList) {
String field1 = aSomeObjectsList.get1();
String field2 = aSomeObjectsList.get2();
String field3 = aSomeObjectsList.get3();
String field4 = aSomeObjectsList.get4();
for (ObjectList someObject : ret) {
if (
field1.trim().equals(someObject.get1())&&
field2.trim().equals(someObject.get2())&&
field3.trim().equals(someObject.get3())&&
field4.trim().equals(someObject.get4())
){
ret.add(aSomeObjectsList);
}
}
}
return ret;
}
But i guess I am doing something wrong because it doesn't return anything, and I know it has duplictates under this 4 field criteria
Thanks in advance
for (Object someObject : ret) {
if (
field1.trim().equals(someObject.get1())&&
field2.trim().equals(someObject.get2())&&
field3.trim().equals(someObject.get3())&&
field4.trim().equals(someObject.get4())
){
ret.add(aSomeObjectsList);
}
}
The above loop wouldn't work, since it has the size of zero.
Here you go,
public Set<ObjectList> duplicates(ArrayList<ObjectList> someObjectsList) {
Set<ObjectList> originals = new HashSet<ObjectList>();
Set<ObjectList> duplicates = new HashSet<ObjectList>();
for ( ObjectList aSomeObjectsList: someObjectsList) {
boolean added = originals.add(aSomeObjectsList);
if(!added){
duplicates.add(aSomeObjectsList);
}
}
return duplicates;
}
This would work, provided your ObjectList class have the correct implementation of hashCode() and equals() methods.
Disclaimer: This implementation will not provide the information about how many times a particular object was duplicated in the provided list. It will just tell you that a particular object was duplicated. I assumed that that was your real intention. If you wanna count, how many times, you have to modify the code accordingly.
Hint/Suggestion: You should override the equals() method and place your field equality check in there instead, once and for all.
This shouldn't compile - if aSomeObjectsList is an Object then it doesn't have methods get1(), get2(), etc.
Your logic won't work because you aren't checking each element in your input List against the other elements in the input List; rather, you're trying to check the return List.
Also, this is not a really efficient way to check for duplicates in a collection. A better way would be to use a HashMap, where you could check set membership in roughly constant time. If you have to use a List, then sort it first (assuming your objects have a natural ordering) and check adjacent members for equality.
Barring those two, just use List.contains().
Here's a way you can do this. I have defined a basic class ObjectList that shows a way to implement equals and hashCode. Note that this assumes that all the internal variables are non-null. If these variables can contain null then you will need to check for that when computing the equals/hashCode. Also, the objects in this class must also themselves properly implement equals/hashCode.
public class ObjectList {
private int h;
private Object obj1;
private Object obj2;
private Object obj3;
private Object obj4;
#Override
public boolean equals(final Object o) {
if (!(o instanceof ObjectList))
return false;
final ObjectList that = (ObjectList) o;
return that.obj1.equals(obj1) && that.obj2.equals(obj2)
&& that.obj3.equals(obj3) && that.obj4.equals(obj4);
}
#Override
public int hashCode() {
// caches the hashcode since it could be costly to recompute every time
// but this assumes that your object is essentially immutable
// (which it should be if you are using equals/hashCode. If this is not
// true and you want to just temporarily use this when doing the duplicate
// test, move the h variable definition from the object level to this method
// and remove this if statement.
if (h != 0)
return h;
h = obj1.hashCode();
h = h * 31 + obj2.hashCode();
h = h * 31 + obj3.hashCode();
h = h * 31 + obj4.hashCode();
return h;
}
}
public Collection<ObjectList> duplicates(
final Collection<ObjectList> someObjectsList) {
final Set<ObjectList> unique = new HashSet<ObjectList>(someObjectsList);
final ArrayList<ObjectList> ret = new ArrayList<ObjectList>(someObjectsList);
for (final ObjectList o : unique) {
ret.remove(o);
}
// The ret list now contains the duplicate instances; instances
// with more than two occurrences will occur multiple times still in
// this list.
return ret;
// If you want a list of unique duplicate instances then, comment out the above
// return and uncomment this one.
// return new HashSet<ObjectList>(ret);
}
Using Collection<ObjectList> is better, if you can do that, for both the parameter and returned value so you can vary the implementations (ArrayList, Set, etc).

Casting a Object to HashMap

I'm having trouble working out how to count instances of Values in a HashMap.
I have seen that there is methods attached to the Object class that look as if they are able to help me, so I've tried to cast those in to work but I must be doing something wrong somewhere.
If there's an easier way, I haven't found it yet. NB: Library is my HashMap.
public void borrowBooks(String id, String name, String sid, String sname) {
if((getKeyFromValue(Books, name).equals(id))&&(getKeyFromValue(Students, sname).equals(sid))){
if((Object)Library.countValues(sid)!=5){
Library.put(id, sid);
}
else{
System.out.println("You have exceeded your quota. Return a book before you take one out." );
}
}
}
Which doc are you looking at ? The Javadoc for Hashmap doesn't specify a countValues() method.
I think you want a HashMap<String, List<String>> so you store a list of books per student (if I'm reading your code correctly).
You'll have to create a list per student and put that into the HashMap, but then you can simply count the entries in the List using List.size().
e.g.
if (Library.get(id) == null) {
Library.put(id, new ArrayList<String>());
}
List<String> books = Library.get(id);
int number = books.size() // gives you the size
Ignoring threading etc.
First: There is (almost) no point in ever casting anything to Object. Since everything extends Object, you can always access the methods without casting.
Second: The way you're casting actually casts the return value, not the Library. If you were doing a cast that was really necessary, you would need an extra set of parentheses:
if(((Object)Library).countValues(sid) != 5)
Third: There is no countValues method in either HashMap or Object. You'll have to make your own.
This is the general algorithm to use (I'm hesitant to post code because this looks like homework):
initialize count to 0
for each entry in Library:
if the value is what you want:
increment the count
int count = 0;
for(String str : Library.values())
{
if(str == sid)
count++;
if(count == 5)
break;
}
if(count < 5)
Library.put(id, sid);
else
System.out.println("You have exceeded your quota. Return a book before you take one out." );

Categories