In an ArrayList, I have the same kind of objects. Each object has an id, name, and number as their fields. There is a chance that more than one object will have the same phone number. How can I make the ArrayList in such a way that all the ArrayList objects have distinct phone numbers?
override in your class methods equals() and hashCode(). In equals you will compare by phone number. Generate hashcode from your phone number too.
Now you are ready to use Set interface which will compare your objects by phone numbers automatically and exclude duplicates.
example below:
public class Test {
private int id;
private String name;
private String phoneNumber;
public Test(int id, String name, String phoneNumber) {
this.id = id;
this.name = name;
this.phoneNumber = phoneNumber;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test test = (Test) o;
return phoneNumber.equals(test.phoneNumber);
}
#Override
public int hashCode() {
return phoneNumber.hashCode();
}
}
now instead of using List<Test> arr = ArrayList<Test>(), use Set<Test> mySet = new HashSet<Test>().
Try Set.
A collection that contains no duplicate elements.
First solution that comes to my mind is to use a HashMap.
Simply create a HashMap with the 'phonenumber' as key and your object as the value. After adding all the elements, you will have the list of objects with unique phone numbers. Simply iterate over this to create the List that you need.
Related
I have a class of persons.
Public class Person{
private String name = "";
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now I have another class and inside the class I declared an arraylist
public class AddPerson {
public ArrayList<Person> pers = new ArrayList<Person>();
//here we add some persons to the arraylist
pers.add(new Person("Simon"));
pers.add(new Person("Oscar"));
pers.add(new Person("Alfred"));
String name = "Simon";
pers.contains(name); //return false
pers.equals(name); //return false
//I also want to be able to return the value and index of the name in arraylist if it exsists.
if(pers.contains(name)) //return index and value
}
When I try to check if two strings are equal or if a string is already in my list I get both false. I did some research and I saw that I need to override my equals method (and mabey hash and contains method as well). I do not know how to do it and I could not find a good reference how to do it. Please help me to achive that.
Here the problem is you are comparing a Person object with String object using the contains method.So actually in this case there is no point of implementing equals() method and hashCode() methods or using the contains() method to solve this .Only you have to do is check if person's attribute name is equal to your comparing String called name.
Sample solution:
String name="Simon";
Person result = null;//To store the person object if a person name Simon found in the list
int personIndex = -1; //To store the index of founded person
int indexCount =-1;//To maintain the current index value of arrayList
for(Person tempPerson:pers){//Iterating the list to find a person name Simon
indexCount++;
if(pers.getName().equals(name)){
personIndex = indexCount;
result = tempPerson;
}
}
Now you can use the values in personIndex and indexCount variables for future calculations.You can use a condition like if(personIndex >= 0) to check if really a person found with the comparing name after the iteration and then you can get the result variable value.
That is because you are trying to compare a string ("simon") and an object Person built from a string (Person("Simon")). These are two different objects, and it is thus normal to have false as a result.
Whether you want to compare two Person (this would make sense) or you are actually trying to compare a string and a person are it is most certainly a bad idea (you can't actually compare apples and oranges, well this is the same here).
What you might want to do is whether
to override Person's equals method to, for example, return true if they have the same name. => comparing Persons
to iterate on your pers array and fetch it's name property via getName() to compare it with you name string => comparing Strings
1 =>
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Person person = (Person)o;
return name.equals(person.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
2 =>
for (final Person person : pers) {
if(name.equals(person.getName())){
// ...
}
}
I have one ArrayList of 10 Objects.
List<Person> persons = new ArrayList<>();
persons.add(new Person("Jean", "Pol", "receptionist", 29));
persons.add(new Person("Jef", "Snijders", "guardener", 42));
persons.add(new Person("Piet", "Peters", "truck driver", 54));
persons.add(new Person("Peet", "Polders", "professor", 63));
persons.add(new Person("Nell", "Van Den Walle", "student", 19));
persons.add(new Person("Nady", "Van Toren", "cleaning", 27));
persons.add(new Person("Jenny", "De Koster", "police", 39));
persons.add(new Person("Malena", "Zetterman", "air traffic controler", 45));
persons.add(new Person("Medina", "Zegers", "test engineer", 25));
persons.add(new Person("Horaire", "Safrina", "manager", 39));
Another method in the applications creates an changed object:
Person changed = new Person("Jean", "Pol", "officer", 30);
How do I find this object in the list, and update the list?
(this should actually update the first object in the list)
This is the Person bean:
public class Person {
private String firstName;
private String lastName;
private String jobTitle;
private int age;
public Person() {
}
public Person(String firstName, String lastName, String jobTitle, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.jobTitle = jobTitle;
this.age = age;
}
// Getters and setters
...
}
Changing an element in the List can be done by :
persons.set(0,changed);
However, finding the index of the element to change requires iterating over the entire List. You should consider using a HashMap instead (where the key identifies the Person).
Then
persons.put (personID, changed);
will replace the Person whose ID is personID (you'll need to have some unique property in the Person class, and override hashCode and equals in order to make that work).
You should tell java about "On what basis should i consider two person equals"? For that you have to override equals() method and do an equality check based on firstName and lastName. However since it is a list, so you will have to iterate over it and use contains(Person p) method to check if it exists (Which will use equals method). Once you find a matching Person object, you can replace it (using the index).
first decide which property or properties can be used to verify if 2 objects are equal then override equals and hashcode for persons and then iterate and compare then replace when found.
the best approach to find the object is to override two methods equals(Object o) and hashCode() within your Person class, this will define a unique Person
your Person class:
class Person {
...
#Override
public boolean equals(Object o){
// your code here
}
#Override
public int hashCode(){
//your code here
}
}
if ordering is not important to you , you can use HashMap
for example :
Person p;//
myMap.put(p.hashCode(),p);
then from other part of your application you get your person;
Person otherP;//
myMap.put(otherP.hashCode(), otherP) // this will replaces the previous person with the same hashCode with the modified code
if you don't want to add a person that is not already there, you can check if it exists first
if(myMap.containsKey(otherP.hashCode()){
myMap.put(otherP.hashCode(), otherP);//
}
generate hashcode and equals methods in your bean class for the variable you want to check for similarity (in your case the firstName property in person class).if using eclipse then pressing ctrl+shift+s shows you the option to generate hashcode and equals methods.
what this does is to override the default equals method. Please make sure that you are selecting only the properties which you know will be same.
if (List.contains(new_object)) { // checking if object is in the list
int indexPos = List.indexOf(new_object); // getting the index if there
dbStockObjList.set(indexPos, new_object);//adding it in the index
}
the hashcode and equals methods for your bean would look like this:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
return true;
}
hope this answers your question properly.
You can use the List#indexOf(obj) method to get the index of the "identical" object, and update it using List#set(index, object).
Note that it will require you to override equals() method for your object.
Also note: this operation is inefficient, and if the list is large and the number of changes is frequent - consider switching from a list to a "smarter" data type, such as a Set.
I want to add unique objects into list on the basis of property of object.
class Employee {
protected long employeeId;
protected String firstName;
protected String lastName;
Employee(long employeeId,String firstName,String lastName){
this.employeeId = employeeId;
this.firstName = firstName;
this.lastName = lastName;
}
}
I want to insert object into list on the basis of unique 'employeeId' and 'firstName' , combination should be unique while inserting object into list.
If you want certain containers to work that are able to prevent duplicates of your Employee from being added you need to define how equals is calculated in Employee.
public class Employee {
//...
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder()
// if deriving: .appendSuper(super.equals(obj))
.append(employeeId, rhs.employeeId)
.append(firstName, rhs.firstName)
.append(lastName, rhs.lastName)
.isEquals();
}
}
If you want certain containers to work that are able to look up your Employee quickly you need to define how hashcode is calculated in Employee.
public class Employee {
//...
#Override
public int hashCode() {
int hash = 1;
hash = hash * 17 + employeeId;
hash = hash * 31 + firstName.hashCode();
hash = hash * 13 + lastName.hashCode();
return hash;
}
}
Most modern IDE's will offer a re-factoring to do this for you. Use the same fields in both so they change together.
Since you don't want duplicates you're best bet is to not use ArrayList but something that pays attention to the hash and will enforce uniqueness for you. Whenever I'm picking a container in java I look at this:
To have all of those available to you, you need to implement not only hashcode and equals but comparator as well.
Just to be clear, the point of the hash is to provide lookup speed. The point of equals is to define what objects are considered identical. The point of comparator is to provide an ordering for the objects.
If you want to include the less frequently used containers try this:
This can be achieved by overwriting the methods equals() and hashCode() - then you can turn to existing java.util collection classes (like HashSet) that use these methods when comparing objects.
Here, equals() & hashCode() methods are overridden to meet the given requirements.
class Employee {
protected long employeeId;
protected String firstName;
protected String lastName;
Employee(long employeeId,String firstName,String lastName){
this.employeeId = employeeId;
this.firstName = firstName;
this.lastName = lastName;
}
public boolean equals(Object o){
if(o == null) return false;
if(!(o instanceof) Employee) return false;
Employee other = (Employee) o;
if(this.employeeId != other.employeeId) return false;
if(! this.firstName.equals(other.firstName)) return false;
return true;
}
public int hashCode(){
return (int) employeeId * firstName.hashCode();
}
}
Here, if two Employee objects are equal, they will also have the same hash code. But, even still two Employee objects can be not equal having the same hash code.
Ex: The hash code is the employeeId is rounded down to an int. That means that many employee id's could result in the same hash code, but these Employee objects would still not be equal, since they don't have the same employee id.
I have a collection of objects, A.
class A{
String name;
Collection<B> listOfB;
}
class B {
String address;
String phone;
int age;
}
I want to create new collection of A objects, where 2 objects have the same name, address, and phone. Can anyone tell me if this is the best way to do this?
I create a map of Key-A. The key would be as follows:
Key {
String name;
String address;
String phone;
}
I only as A objects to the list if their corresponding Key is not present.
If I understand your question correctly you want a map Map<Key, A>. The important thing is that you define equality and the hash code (in case you want a hash map) for the Key:
class Key {
String name;
String address;
String phone;
#Override // override in Object
public boolean equals(Object other) {
if(!other instanceof Key) return false;
Key otherKey = (Key) other;
return name.equals(otherKey.name) && address.equals(otherKey.address) && phone.equals(otherKey.phone); // check for null if fields can be null
}
#Override // override in Object
public int hashCode() {
return name.hashCode() ^ address.hashCode() ^ phone.hashCode(); // or something along those lines
}
}
Also good idea to create a constructor for the Key and make the fields private and final.
I'm not sure how this key is derived though. Ideally, the Key would somehow be derived from A, or - even better - A would have a hashCode and equals method so you do not need a map but you can use a Set. This really depends on the data you want to model though and your question is not clear enough to give a specific recommendation.
First, implement hascode and equals method in class B.
In equals method return true when name,phone and adress are the same.
Second time, create your map like this=
HashMap<B,A> myMap;
A key in a map is always unique.
I have a Java class as
class Students{
private String fName;
private String lName;
private String uName;
public Students(String fName, String lName, String uName) {
this.fName = fName;
this.lName = lName;
this.uName = uName;
}
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getlName() {
return lName;
}
public void setlName(String lName) {
this.lName = lName;
}
}
Also I call this using
public class TestClass {
public static void main(String[] args) {
Students students1 = new Students("xyz","abc","xyzAbc");
Students students2 = new Students("poi","son","poison");
Students students3 = new Students("yog","jos","yogjos");
Students students4 = new Students("xyz","abc","xyzAbc");
Students students5 = new Students("pon","son","xyzAbc");
Students students6 = new Students("yog","jos","someotherUName");
Students students7 = new Students("yog","jos","someotherUName2");
List studentList1 = new ArrayList();
List studentList2 = new ArrayList();
studentList1.add(students1);
studentList1.add(students2);
studentList1.add(students3);
studentList2.add(students4);
studentList2.add(students5);
studentList2.add(students6);
}
}
Now I want a filtered list which would contain only unique "uName" values. Thus I want the comparison between "uName" field of each list and remove common ones.
At the end I would want 2 filtered list for studentList1 and studentList2.
I read about the removeAll method, but it seems to work with List of Integer/String data and not with List of Objects (as in my case).
You can put your list to set and then (if you need) to take it back:
new ArrayList(new HashSet<String>(list)) creates list that contains only unique elements from source list.
1. If you want each list to have unique uName value, then you can use TreeSet from java.util.Collection along with Interface Comparator from java.util.Comparator.
2. If you want to merge both the list and have unique uName, then combine both the list and then use TreeSet and Comparator.
3. Comparator gives the flexibility to compare in more than one way...
You can still use removeAll if the Objects in the List implement equals() properly.
AbstractCollection, which is the base for most kind of List implementations (including ArrayList) uses contains() in its implementation of removeAll. ArrayList's implementation of contains relies on indexOf(), which lastly uses equals().
You could implement equals() in your Student class to specify that an Student is equal to another if and only their uName fields are equal.
Please note that equals has associated semantics (see its javadoc), and you should be careful when choosing how to implement it. Consider if two student instances really represent the same student when their uNames are equal. In my opinion, this sounds like a very specific requirement of how to sort these things out and should not impact the semantics of the class.
You'll be much better off with #AlexR or #KumarVivekMitra's approach.
Firstly, you should be typing your lists:
List<Students> studentList1 = new ArrayList<Students>();
Secondly, implement hashCode() and equals() on your Students class that both delegate to uName:
public boolean equals(Object o) {
return o instanceof Students && ((Students)o).uName.equals(uName);
}
public int hashCode() {
return uName.hashCode();
}
Now removeAll() will work just fine.
Another option is to use Set, which only allows unique values as determined by the equals() method. If you add the above methods to your class, you could just do this:
Set<Students> students = new HashSet<Students>();
then add what you like to it and there will only ever be unique uName students in it.
btw, you should name your class in the singular - ie Student not Students.
You could also try using the apache commons CollectionUtils.disjunction. (link: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html#disjunction(java.util.Collection, java.util.Collection))
Your class Student should override methods hashcode and equals, so youy object can be unique by name. Here you can read how to do that.
Also note that all objects which are maintained in some collection should have those methods overriden, so you always know how are they compared.
In next step you can use removeAll method or the solution with Set, it's up to you :-)
Set example
List<String> list = new ArrayList(new HashSet<String>(studentList)); // here is your unique list
Or you could use custom Comparator instead of overriding hashcode and equals but if you want your students always unique, you should override them
A full working solution could be as follows.
Class Student{
.....
......
.....
public boolean equals(Object o) {
return o instanceof Students && ((Students)o).uName.equals(uName);
}
public int hashCode() {
return uName.hashCode();
}
}
Set studentList1 = new hashSet();
Set studentList2 = new hashSet();
Put your elements in these Sets.
Also if you want unique non-matching elements in both Sets. then write as follows.
studentList1.removeAll(studentList2 );