Compare arraylist objects in java - java

I have list of objects in an arraylist and I need to compare every objects with other objects available in the arraylist;
For Example:
Class Employee {
private String empname;
private Long empid;
private boolean empsex;
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public Long getEmpid() {
return empid;
}
public void setEmpid(Long empid) {
this.empid = empid;
}
public boolean isEmpsex() {
return empsex;
}
public void setEmpsex(boolean empsex) {
this.empsex = empsex;
}
}
public list<Employee> getEmpList() {
List<Employee> empList = new ArrayList<Employee>();
Employee emp = new Employee();
for(...) {
//insert values to emp object for n number of times;
}
empList.add(emp); //add emp.object to empList;
return empList;
}
Now while inserting these values to UI; Need to compare objects in the list; where any two or more objects matches with each other or not?

Based on the assumption that you want to eliminate the duplicates from the list and do not show duplicates on GUI.
Use Set collection, it automatically takes care of duplicates.
A collection that contains no duplicate elements. More formally, sets
contain no pair of elements e1 and e2 such that e1.equals(e2), and at
most one null element. As implied by its name, this interface models
the mathematical set abstraction.
Override equals() and hashcode() methods.
References:
On equals and hashcode in Java
Overriding equals and hashcode

You could override equals method for that class to compare the objects of the same class the way you want.
Default equals method:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Link about overriding equals:
http://javarevisited.blogspot.com/2011/02/how-to-write-equals-method-in-java.html

One simple method of doing this is to just do a double for loop.
public static List<Employee> getList(List<Employee> oldList)
{
List<Employee> empList = new ArrayList<Employee>();
for (int i = 0; i < oldList.size; i++)
{
for (int j = 0; j < oldList.size; j++)
{
//compare oldList.get(i) with oldList.get(j)
//if match, set some boolean
}
//if duplicate found, delete one copy, or add one to new list, etc
}
This allows you to go through each element in the outer loop, and compare to every other element in the inner loop.

I guess employee id (empid) is unique for each emplyee, yes?
If so, use a hash instead where empid is the key and employee object is the value.
Map<Long, Employee> empmap = new HashMap<Long, Employee>();
empmap.put(currentEmployee.getEmpid(), currentEmployee)

Related

How to get rid of NullPointerException when removing elements from array? [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed last month.
Given the following task. We have an Employee and a Company classes. Each instance of Employee class is stored in array Employee[] employees in the Company class. I need a method which removes an instance of Employee in the array Employee[] employees by id.
I managed to write the following code:
public class Employee {
protected final int id;
protected String name;
public Employee(int id, String name) {
this.id = id;
this.name= name;
}
public int getId() {
return id;
}
}
public class Company {
private Employee[] employees;
private int size;
private static final int defaultCapacity = 5;
public Company() {
this(defaultCapacity);
}
public Company(int capacity) {
if (capacity <= 0)
throw new RuntimeException("capacity is required");
employees = new Employee[capacity];
}
public Employee removeEmployee(int id) {
Collection<Employee> employeeList = Arrays.asList(employees)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Employee[] employeeArray = employeeList.toArray(Employee[]::new);
for (int i = 0; i < size; i++) {
if(employeeArray[i].getId() == id) {
Employee removedEmployee = employees[i];
employeeList.remove(employeeArray[i]);
employees = employeeList
.stream()
.filter(Objects::nonNull)
.toArray(Employee[]::new);
return removedEmployee;
}
}
return null;
}
}
The problem is that my method public Employee removeEmployee(int id) throws NullPointerException if an element for removal is not found.
Question:
How can I rewrite the method public Employee removeEmployee(int id) using, for instance, Streams API and Optional in oder to get rid of NullPointerException in the method public Employee removeEmployee(int id)?
N.B.: The length of the array Employee[] employees declared in the class Company must be reduced after the element has been successfully removed.
There is a lot of ways to get rid of the NullPointerException here.
If you want to keep using the stream API, you may want to use filter and findAny.
For example, you could modify the method to the following:
public Employee removeEmployee(int id) {
Optional<Employee> employee = Arrays.stream(employees)
.filter(Objects::nonNull)
.filter(x -> x.getId() == id).
.findAny();
if(employee.isEmpty())
return null;
employees = Arrays.stream(employees).filter(x -> x != employee.get()).toArray(Employee[]::new);
return employee.get();
}
However, I would highly advise using a List or even a Map instead of an Array for employees as this makes things way easier and faster:
public Employee removeEmployee(int id){
Optional<Employee> toRemove = employees.stream().filter(x -> x.getId() == id).findAny();
if(toRemove.isEmpty())
return null;
employees.remove(toRemove.get());
return toRemove.get();
}
Or not to use the Stream API:
public Employee removeEmployee(int id){
int idx;
for(idx = 0; idx < employees.length; idx++){
if(employees[idx] != null && employees[idx].getId() == id)
break;
}
if(idx == employees.length)
return null;
Employee value = employees[idx];
Employee[] newArr = new Employee[employees.length - 1];
// the parameters here are left as an exercise to the reader :P
System.arraycopy(newArr, ...);
System.arraycopy(newArr, ...);
employees = newArr;
return value;
}
The length of the array Employee[] employees declared in the class Company must be reduced after the element has been successfully removed.
Streams doesn't buy you a lot in this case.
What you're supposed to do is to find the element with the target id, and if such an element exists, allocate a new array in memory with a length smaller by 1 copy all the elements apart from the one that was found, and assign employees with the reference to the new array.
To reduce the length, we can make use of the System.arraycopy(). First copy the elements before the target, and then after the target.
That's how it would look like with a plain index-based for-loop.
public Employee removeEmployee(int id) {
Employee result = null;
int index = -1;
for (int i = 0; i < employees.length; i++) {
if (employees[i] != null && employees[i].getId() == id) {
result = employees[i];
employees[i] = null;
break;
}
}
if (result != null) {
reduceLength(index);
}
return result;
}
public void reduceLength(int i) {
Employee[] newEmployees = new Employee[employees.length - 1];
System.arraycopy(employees, 0, newEmployees, 0, i);
System.arraycopy(employees, i + 1, newEmployees, i, employees.length - (i + 1));
employees = newEmployees;
}
If you want to do weird stuff and use Stream API and Optional at all costs, here how it can be done (but I would recommend to stick with the code above):
public Optional<Employee> removeEmployee(int id) {
Optional<Integer> index = IntStream.range(0, employees.length)
.filter(i -> employees[i] != null)
.filter(i -> employees[i].getId() == id)
.boxed() // otherwise will get OptionalInt which lacks map() method
.findFirst();
Optional<Employee> result = index.map(i -> employees[i]);
index.ifPresent(this::reduceLength);
return result;
}
Considering it's homework and constraints mentioned, i believe you are supposed to do all the work using the array only.
I'll provide some guideline and leave the actual implementation to you:
public class Company {
private Employee[] employees;
private int size;
public Employee removeEmployee(int id) {
int index = -1;
//find the index of employee with required id, you have mostly done that
if (index == -1) {
return null;
}
//save found employee to variable
//remove from array
//shift array to the left
//do not forget to use and reassign size variable where appropriate
}
//some extra
public void addEmployee(Employee employee) {
//resize array if necessary
//add employee at correct position in array
//do not forget to use and reassign size variable where appropriate
}
}
If you get stuck, you can look at the ArrayList class, your task is basically a simplified version of it. I strongly advise you to use this as source of inspiration only and not to copy the source code!!!

Use iterator to check an ascending order (row major order) arraylist of a specific object with a number id?

I have a class that implement an iterator, each object in this class has an id which refers a number.
public class Shelf extends Observable implements Iterable<Book>{
final static int NumRow = 10;
final static int NumCol = 10;
Book[][] books = new Book[NumRow][NumCol];
# Here is the code for Iterator<Book> iterator();
I have already implement the iterator with hasNext, and Next methods
class Book implement Comparable<Book>{
private int id
public int getId() {return id;}
How can I check if the entire arraylist is in ascending order by each object's id?
This is what I wrote
boolean ascending order(){
boolean check = true;
Iterator<Book> iter = shelf.iterator();
while (iter.hasNext()){ \\How can I wrote here?
}
return check;
How can I compare the current id with the next id?
You can try the following code.
public boolean checkAscendingSort(List<Book> books){
for(int i=1; i<books.size(); i++){
if(books.get(i).getId() < books.get(i-1).getId()){
return false;
}
}
return true;
}
You can store the value of the id and check at the next element, then change the value of previous
private static boolean isOrdered() {
Iterator<Book> ite = shelf.iterator();
int previousId = Integer.MIN_VALUE;
while (ite.hasNext()) {
Book next = ite.next();
if (next.getId() < previousId) {
return false;
}
previousId = next.getId();
}
return true;
}

How do I search an ArrayList of Objects

I am creating an ArrayList of Accounts (an object) and the Account constructor is
public Account(String name, int accNum, int balance)
{
myName = name;
myAccountNum = accNum;
myBalance = balance;
}
I want to know how to check the ArrayList to determine if a given accountNumber exists in it, and if it does, return true
private static ArrayList<Account> accounts = new ArrayList<Account>();
My initial thought was this, but I do not think that this works
if(accounts.contains(tempAccNum))
{
//executes code that I have
}
For the Java ArrayList, contains performs an object equality comparison. To use .contains, you would need to
Implement the .equals() method for the Account class, and have it check only the this.myAccountNum property against the account number of the input Account.
Create a dummy Account with the desired account number to pass into contains.
A better method would involve evaluating an iterator, and checking the account numbers at each step. Here I assume that myAccountNum is a public property of the Account class.
Iterator<E> it = Accounts.iterator();
while (it.hasNext()) {
Account acc = it.next();
if(acc.myAccountNum == tempAccNum)
return true;
}
For ArrayList specifically, using .get with an index is not too bad:
for(int index = 0; index < Accounts.size(); ++index) {
if(Accounts.get(index).myAccountNum == tempAccNum)
return true;
For other List types, using indices can be very poor.
Ways to iterate over a list in Java
I will suggest you to make it simple by just implementing an equals() method for account class.
#Override
public boolean equals(Object o){
if(o==null)return false;
if(o.getClass()!=this.getClass())return false;
Account demo = (Account)o;
if(!demo.myName.equals(this.myName))return false;
if(demo.myAccountNum != this.myAccountNum)return false ;
if(demo.myBalance = this.myBalance)return false ;
}
then use contains method
First add getter for accNum in Account model
Then try this
public boolean containsAcc(int accno) {
for(int i=0;i<accounts.size();i++) {
if(accounts!= null && accounts.get(i).getMyAccountNum()==acno) {
return true;
}
}
return false;
}
Here getMyAccountNum() is the getter declared in Account model(shown below)
Then check this
if(containsAcc(tempAccNum))
{
//your code
}
Your Account model should be like this
public class Account {
String myName;
int myAccountNum;
int myBalance;
public Account(String name, int accNum, int balance)
{
this.myName = name;
this.myAccountNum = accNum;
this.myBalance = balance;
}
public int getMyAccountNum() {
return myAccountNum;
}
}

Removing Duplicate Entries in Array - Java

For Java practice, I am trying to create a method inside my EmployeesDirectory Class that:
Removes Duplicate entries from the array
The array should be the same length after removing duplicates
Non-Empty entries should be making a contiguous sequence at the beginning of the array - and the actualNum should keep a record of the entries
Duplicate Means: Same Name, Position and Salary
Here is my Current Code:
I am unsure on how to implement this - any help would be appreciated
class EmployeeDirectory {
private Employee dir[];
private int size;
private int actualNum;
public EmployeeDirectory(int n) {
this.size = n;
dir = new Employee[size];
}
public boolean add(String name, String position, double salary) {
if (dir[size-1] != null) {
dir[actualNum] = new Employee(name, position, salary);
actualNum++;
return true;
} else {
return false;
}
}
}
I'd rather you did not write a distinct method for removing duplicates. If I were you, I would search for duplicates in add method and then instantly decide whether I need to add Employee.
Also, why don't you use Sets (link for HashSet) instead of arrays for your purpose? Sets by their own definition disallow adding duplicates, so they seem to be appropriate as a solution
First of all, Override equals and hashCode methods in Employee class as follow
#Override
public boolean equals(Object other) {
if(this == other) return true;
if(other == null || (this.getClass() != other.getClass())){
return false;
}
Employee guest = (Employee) other;
return Objects.equals(guest.name, name)
&& Objects.equals(guest.position, position)
&& Objects.equals(guest.salary, salary);
}
#Override
public int hashCode() {
return Arrays.hashCode(new Object[] {
name,
position,
salary
});
}
Then you can use Stream API distinct method to remove duplicates
Returns a stream consisting of the distinct elements (according to
Object.equals(Object)) of this stream.
You can do it like so
Employee e1 = new Employee("John", "developer", 2000);
Employee e2 = new Employee("John", "developer", 2000);
Employee e3 = new Employee("Fres", "designer", 1500);
Employee[] allEmployees = new Employee[100];
allEmployees[0] = e1;
allEmployees[1] = e2;
allEmployees[2] = e3;
allEmployees = Arrays.asList(allEmployees).stream().distinct()
.toArray(Employee[]::new);
Arrays.asList(allEmployees).forEach(System.out::println);
Output: (keeping both empty and non-empty entries)
John developer 2000.0
Fres designer 1500.0
null
Unfortunately, I have not got the Employee class to verify my code, but try this:
void removeDuplicates() {
int length = dir.length;
HashSet set = new HashSet(Arrays.asList(dir));
dir = new Employee[length];
Employee[] temp = (Employee[]) set.toArray();
for (int index = 0; index < temp.length; index++)
dir[index] = temp[index];
}
The code must remain the size of array after deletion the duplicates. At the beginning of array there must be valid Employees, at the end - nulls.
And don't forget to add this at the beginning of your .java file
import java.util.Arrays;
import java.util.HashSet;
If your task states as "remove duplicates from array" (i. e. you cannot use ArrayList or control when adding items), you can use the following approach:
public void removeDuplicates() {
Set<Employee> d = new HashSet<>(); // here to store distinct items
int shift = 0;
for (int i = 0; i > dir.length; i++) {
if (d.contains(dir[i])) { // duplicate, shift += 1
shift++;
} else { // distinct
d.add(dir[i]); // copy to `d` set
dir[i - shift] = dir[i]; // move item left
}
}
for (int i = d.size(); i < dir.length; i++)
dir[i] = null; // fill rest of array with nulls
actualNum = d.size();
}
Here, shift variable stores number of duplicates found in the array so far. Every distinct item is moved to shift positions left in order to make sequence continuous while keeping initial ordering. Then remaining items are altered to nulls.
To make hash-based collections work with Employee instances correctly, you also need to override hashCode() and equals() methods as follows:
public class Employee {
//...
#Override
public int hashCode() {
return Objects.hash(name, position, salary);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!o.getType().equals(this.getType()) return false;
Employee e = (Employee) o;
return Objects.equals(e.name, name)
&& Objects.equals(e.position, position)
&& Objects.equals(e.salary, salary); // or e.salary == salary, if it primitive type
}
}

Unique Java Objects in a LinkedHashSet

I want to create a top 5 list of unique key value pairs sorted according to a value.
I have tried creating a Hashmap but since the original list that i read from JSON is sorted Hashmap overwrites the last value so they key will have the smallest value instead of the largest.
The solution was to use LinkedHashSet, to ensure uniqueness and keep the order. But since i am storing a key, value pairs i decided to create a new class and save them as objects.
I know that i had to implement comparable but apparently there is no comparison happening and the LinkedHashSet is not unique.
My Code is:
public class cellType implements Comparable<Object> {
private String type;
private double confidence;
#Override
public String toString() {
return "type=" + type + " - confidence=" + confidence ;
}
public cellType(String type, double confidence) {
super();
this.type = type;
this.confidence = confidence;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getConfidence() {
return confidence;
}
public void setConfidence(double confidence) {
this.confidence = confidence;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof cellType)) {
return false;
}
cellType ct = (cellType) obj;
return type.equals(ct.getType());
}
#Override
public int compareTo(Object o) {
cellType ct = (cellType) o;
return type.compareTo(ct.getType());
}
}
public static void main(String args[]) throws IOException, JSONException {
String freebaseAddress = "https://www.googleapis.com/freebase/v1/search?query=";
System.setProperty("https.proxyHost", "proxy");
System.setProperty("https.proxyPort", "8080");
JSONObject json = readJsonFromUrl(freebaseAddress + "apple");
LinkedHashSet<cellType> rich_types = new LinkedHashSet<cellType>();
JSONArray array = json.getJSONArray("result");
for (int i = 0; i < array.length(); i++) {
if (array.getJSONObject(i).has("notable")) {
JSONObject notable = new JSONObject(array.getJSONObject(i)
.getString("notable"));
if (rich_types.size() <= 5)
rich_types.add(new cellType(notable.getString("name"), (Double) array.getJSONObject(i).get("score")));
}
}
System.out.println(rich_types);
}
The output is:
[type=Monarch - confidence=79.447838, type=Monarch - confidence=58.911613, type=Monarch - confidence=56.614368, type=Founding Figure - confidence=48.796387, type=Politician - confidence=38.921349, type=Queen consort - confidence=36.142864]
I think you mean you want to use TreeMap (Map not Set) to use Comparable keys to sort them. LinkedHashSet is a collection of elements which keep the order they were added.
It sounds like what you want is
if (rich_types.size() <= 5) {
cellType ct = new cellType(notable.getString("name"), (Double) array.getJSONObject(i).get("score"));
if(!rich_type.contains(ct))
rich_types.add(ct);
}
You need to implement hashCode() too.
Anyone who even considers implementing equals() and hashCode() needs to read at least this chapter of Effective Java or better yet the whole book.

Categories