Comparing two list of objects in Java - java

I have two list of Student Objects(listA & listB) which were formed by querying from two different databases. I need to iterate one list and need to make sure it is not present in the other list.
I have used the below comparison code for the same i.e overwritten the equals method and compared using for loops.
Say List A & List B could have 5000 rows each, can you suggest if there are better ways to implement this?
Comparison code:
for (Student dataA:listA) {
for (Student dataB:listB) {
if(dataB.equals(dataA))
break;
}
}
Student Object:
public class Student {
int A;
int B;
String C;
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Student student = (Student) obj;
return A == student.A && B == student.B && C.equals(student.C);
}
}
Edit Note: ListA & ListB can have different number of rows

I would suggest you the retainAll method:
List<Student> listC = new ArrayList();
listC.addAll(listA);
listC.retainAll(listB); //now listC contains all double students
But you should still override the equals method

You could use containsAny method from CollectionUtils (Apache Commons):
if(CollectionUtils.containsAny(listA, listB)){
break;
}

The removeAll command is the way to go, but List lookup is not efficient (linear time), so you get a O(n*m) total time (n is sizeA, m is sizeB); 5000 entries on each, it may be a bit too much.
If possible, you should change it to use Sets (and implements the hashCode and equals methods of your Student classes in case you didn't already!):
Set<Student> studentsA = new HashSet<>();
Set<Student> studentsB = new HashSet<>();
studentsA.removeAll(studentsB);
This gets you O(m*hash(n)).

The general approach is iterate through first list and check for element if it is contained in second list, if it exist add the element to the result list
Below is the complete solution
import java.util.ArrayList;
import java.util.List;
public class CompareListofObj {
public static void main(String[] args) {
List<Student> listStd1 = new ArrayList<Student>();
List<Student> listStd2 = new ArrayList<Student>();
Student std1 = new Student(1, 1, "a");
Student std2 = new Student(2, 1, "b");
Student std3 = new Student(3, 3, "c");
Student std4 = new Student(4, 4, "d");
listStd1.add(std1);
listStd1.add(std2);
listStd1.add(std3);
listStd1.add(std4);
Student std5 = new Student(1, 1, "a");
Student std6 = new Student(2, 1, "b");
Student std7 = new Student(7, 7, "c");
Student std8 = new Student(8, 8, "d");
listStd2.add(std5);
listStd2.add(std6);
listStd2.add(std7);
listStd2.add(std8);
List<Student> listResult = new ArrayList<Student>();
for (int i = 0; i < listStd1.size(); i++) {
if (listStd2.contains(listStd1.get(i))) {
listResult.add(listStd1.get(i));
} else {
}
}
for (int i = 0; i < listResult.size(); i++) {
System.out.println("common elt" + listResult.get(i).getA() + ", " + listResult.get(i).getB() + ", "
+ listResult.get(i).getC());
}
}
}
Student class
package sample;
public class Student {
int A;
int B;
String C;
public Student(int a, int b, String c) {
super();
A = a;
B = b;
C = c;
}
public int getA() {
return A;
}
public void setA(int a) {
A = a;
}
public int getB() {
return B;
}
public void setB(int b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + A;
result = prime * result + B;
result = prime * result + ((C == null) ? 0 : C.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;
Student other = (Student) obj;
if (A != other.A)
return false;
if (B != other.B)
return false;
if (C == null) {
if (other.C != null)
return false;
} else if (!C.equals(other.C))
return false;
return true;
}
}

Related

How to remove duplicate elements from list<String>? [duplicate]

This question already has answers here:
How do I remove repeated elements from ArrayList?
(40 answers)
Closed 3 years ago.
List list = ["f1,f2","f2,f3","f4,f5","f2,f1","f5,f4"];
output list would be
List uniqueList = ["f1,f2","f2,f3","f4,f5"]
I have another solution . If you dont want to prepare another class to compare values inside List . You can separete each value by comma and sort those data. After that you can again converte them to Set of String
public static void main(String[] args) {
List<String> stringList = Arrays.asList("f1,f2", "f2,f3", "f4,f5", "f2,f1", "f5,f4");
Set<String> result = new HashSet<>();
for (String s : stringList) {
String[] elements = s.split(",");
Arrays.sort(elements);
result.add(Arrays.toString(elements));
}
for (String e : result){
System.out.println(e);
}
}
Using an additional class:
static class Pair {
String a, b;
Pair(String s) {
String[] arr = s.split(",");
this.a = arr[0];
this.b = arr[1];
}
static String pairToString(Pair p) {
return p.a + "," + p.b;
}
#Override
public int hashCode() {
return Objects.hash(a, b) + Objects.hash(b, a);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair p = (Pair) o;
return (p.a.equals(a) && p.b.equals(b)) || (p.b.equals(a) && p.a.equals(b));
}
}
Now you can use:
public static void main(String[] args) {
List<String> list = Arrays.asList("f1,f2", "f2,f3", "f4,f5", "f2,f1", "f5,f4");
List<String> strings = list
.stream()
.map(Pair::new)
.distinct()
.map(Pair::pairToString)
.collect(Collectors.toList());
}
I have created a class to model the pairs and override the equals method to treat "f1,f2" and "f2,f1" as equals and then found out the duplicates using HashSet.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class so1 {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[] {"f1,f2","f2,f3","f4,f5","f2,f1","f5,f4"});
List<pair> plist = new ArrayList<pair>();
for (int i = 0; i < list.size(); i++) {
plist.add(new pair(list.get(i)));
}
HashSet<pair> hs = new HashSet<pair>();
for (int i = 0; i < plist.size(); i++) {
if(!hs.add(plist.get(i))){
System.out.println("Found duplicate "+plist.get(i).toString());
}
}
List<String> uniqueItems = new ArrayList<String>();
for (Iterator iterator = hs.iterator(); iterator.hasNext();) {
pair pair = (pair) iterator.next();
uniqueItems.add(pair.toString());
}
System.out.println(uniqueItems);
}
}
class pair{
pair(String inp){
String[] tokens = inp.split(",");
Arrays.sort(tokens);
for(String t: tokens){
elements.add(t);
}
}
List<String> elements = new ArrayList<>();
#Override
public String toString() {
return ""+elements;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((elements == null) ? 0 : elements.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;
pair other = (pair) obj;
if (elements == null) {
if (other.elements != null)
return false;
} else if (!elements.equals(other.elements))
return false;
return true;
}
}
Here are a couple answers from https://www.geeksforgeeks.org/how-to-remove-duplicates-from-arraylist-in-java/
Java 7
// Create a new ArrayList
ArrayList<String> uniqueList = new ArrayList<String>();
// Traverse through the first list
for ( element : list) {
// If this element is not present in uniqueList
// then add it
if (!uniqueList.contains(element)) {
uniqueList.add(element);
}
}
Java 8
List<String> uniqueList = list.stream()
.distinct()
.collect(Collectors.toList());

Removing an instance from a linked list which is using pairs

I am trying to remove an instance from my linked list however when i try searching for the object in the list it returns a value of -1 because it says its not there. what am i doing wrong. my application class is below and that calls the methods in my DataSet class
public class Application {
public static void main(String[] args) {
DataSet<String, Integer> db = new DataSet<>();
db.add("Theo", 4);
db.add("Maria", 5);
db.add("Adam", 4);
db.add("James", 5);
db.add("Charles", 7);
db.add("Nikki", 5);
db.add("Lynne", 5);
db.add("Kendal", 6);
db.add("Kerry", 5);
db.add("Janet", 5);
db.add("Gordon", 6);
db.add("Stepher", 7);
db.add("Sue", 3);
db.add("Ed", 2);
db.add("Adam", 4);
db.displayItems();
/*
System.out.println();
db.sortByFirst();
db.displayItems();
System.out.println();
db.sortBySecond();
db.displayItems();
System.out.println();
(db.findBySecond(5)).displayItems();
System.out.println();
(db.findByFirst("Adam")).displayItems();
System.out.println();
*/ System.out.println(db.remove("Adam", 4));
db.displayItems();
//System.out.println("size = " + db.size());
}
}
and the dataset is:
import java.util.LinkedList;
/**
*
* #param <T>
* #param <S>
*/
public class DataSet<T, S> {
LinkedList<Pair> datastructure = new LinkedList<>();
// Adds a new instance/item to the data structure.
public void add(T first, S second) {
Pair p = new Pair(first, second);
datastructure.add(p);
}
// Displays all itmes in the data structure.
public void displayItems() {
for (int i = 0; i < datastructure.size(); i++) {
System.out.println(datastructure.get(i));
}
}
// Removes all instances with matching criteria (first and second attribute values) and returns the number of instances removed.
public int remove(T first, S second) {
int count = 0;
Pair p = new Pair(first, second);
for (Pair datastructure1 : datastructure) {
Integer num = datastructure.indexOf(p);
System.out.println(num);
Boolean removed = datastructure.remove(p);
System.out.println(removed);
}
//will return count of how many removed
return count;
}
}
and the final class is the pair class
class Pair<T,S> {
private T first;
private S second;
public Pair(T theFirst, S theSecond) {
first = theFirst;
second = theSecond;
}
public T getFirst() {
return first;
}
public S getSecond() {
return second;
}
#Override
public String toString() {
return "(" + first + ", " + second + ")";
}
}
Like Adam pointed out the problem is that you're creating a new pair that is not in the list. What you want to do is to create an equals method in your Pair class and then iterate through your list comparing the elements using this equals method. The method should look like this:
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Pair other = (Pair) obj;
if (this.first != other.first) {
return false;
}
if (this.second != other.second) {
return false;
}
return true;
}
public int remove(T first, S second) {
int count = 0;
Pair p = new Pair(first, second);
for (Pair datastructure1 : datastructure) {
Integer num = datastructure.indexOf(p);
System.out.println(num);
Boolean removed = datastructure.remove(p);
System.out.println(removed);
}
//will return count of how many removed
return count;
}
In above remove method, you are creating a new Pair object. New object means new reference, So datastructure.indexOf(p) will always result -1.
Example:
datastructure contains three pairs:
Pair1 - reference 0x00000001 - "Theo",4
Pair2 - reference 0x00000002 - "Theo",5
Pair3 - reference 0x00000003 - "Theo",6
And we asked to remove "Theo",4. So `p` will be a new object like:
p - reference 0x00000004 - "Theo",4
This means that the reference of p will not match and it will not check the data. Modify the equals method of Pair class as follows:
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj instanceof Pair)
{
Pair pair = (Pair)obj;
if(pair.first.equals(this.first) && pair.second.equals(this.second)){
return true;
}
}
return false;
}

Guava's Sets.Intersection method misbehaving

I have a scenario where in, i need to find intersection of two sets based on a specific field(only color in this case) from the objects contained in the set.
Hence I am trying to find a intersection, subtraction of two Sets(which use a comparator that uses the color of the object to decide on equality of 2 car objects) by using google's Guava. But strangely A intersection B is not equal to B intersection A.
Please help me find where it is going wrong.
why is A intersection B not equal to B intersection A? I am interested in intersection part only.
public class Car {
public String id;
public String color;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((id == null) ? 0 : id.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;
Car other = (Car) obj;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public Car(String id, String color) {
super();
this.id = id;
this.color = color;
}
public Car() {
super();
}
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import com.google.common.collect.Sets;
public class Tester {
public static void main(String[] args) {
final Set<Car> first = new TreeSet<Car>( new Comparator<Car> (){
public int compare( final Car o1, final Car o2 ){
return comp(o1.getColor(), o2.getColor() );
}
} );
first.add(new Car("1","blue"));
first.add(new Car("2","green"));
first.add(new Car("3","red"));
final Set<Car> second = new TreeSet<Car>( new Comparator<Car> (){
public int compare( final Car o3, final Car o4 ){
return comp1(o3.getColor(), o4.getColor() );
}
} );
second.add(new Car("4","black"));
second.add(new Car("5","green"));
second.add(new Car("6","blue"));
second.add(new Car("7","red"));
final Set<Car> intersection1 = Sets.intersection( first, second );
System.out.println("intersection1 size = "+intersection1.size());
for(Car carr : intersection1){
System.out.println("carr.id ="+carr.id+" carr.color ="+carr.color);
}
System.out.println();
final Set<Car> intersection2 = Sets.intersection( second, first);
System.out.println("intersection2 size = "+intersection2.size());
for(Car carr : intersection2){
System.out.println("carr.id ="+carr.id+" carr.color ="+carr.color);
}
System.out.println();
final Set<Car> Pure1 = Sets.difference(first, second);
System.out.println("Pure1 size = "+Pure1.size());
for(Car carr : Pure1){
System.out.println("carr.id ="+carr.id+" carr.color ="+carr.color);
}
System.out.println();
final Set<Car> Pure2 = Sets.difference(second, first);
System.out.println("Pure2 size = "+Pure2.size());
for(Car carr : Pure2){
System.out.println("carr.id ="+carr.id+" carr.color ="+carr.color);
}
System.out.println();
}
static int comp(String a, String b ){
if(a.equalsIgnoreCase(b)){
return 0;
}
else
return 1;
}
static int comp1(String a, String b ){
if(a.equalsIgnoreCase(b)){
return 0;
}
else
return 1;
}
}
Output :
intersection1 size = 3
carr.id =1 carr.color =blue
carr.id =2 carr.color =green
carr.id =3 carr.color =red
intersection2 size = 2
carr.id =5 carr.color =green
carr.id =7 carr.color =red
Pure1 size = 0
Pure2 size = 2
carr.id =4 carr.color =black
carr.id =6 carr.color =blue
Your implementations of comp are incorrect, and your comparators don't satisfy their contracts, so you can get undefined and unpredictable behavior from TreeSet. This has nothing to do with Guava's Sets.intersection method.
The spec for Comparator.compare says:
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
...which your Comparators don't do.
The easiest fix would probably be to use
new Comparator<Car>(){
public int compare(Car o1, Car o2) {
return o1.getColor().compareToIgnoreCase(o2.getColor());
}
}

Java removing object from hashmap

public Map<Object> map = new HashMap<Object>();
map.add(new Object ("a", "b"));
public class Object {
private String a;
private String b;
private String c;
public Object(String a, String b) {
this.a = a;
this.a = b;
this.c = "" + a + b + "";
}
public String getA() {
return a;
}
public String getB() {
return b;
}
public String getC() {
return c;
}
}
I have a hashmap, basically Object.getC() should be a + b in a string.
and in some other class, I need to get the c value and if that hashmap collection index has the exact same c value, it will delete the index:
public static void deleteChest() {
for (int i = 0; i < data.size(); i++) {
if (data.get(i).getItems().length == 0) {
Object c = new Object(data.get(i).getA(), data.get(i).getB());
map.remove(c);
}
}
}
data hashmap should have the same index number as the map hashmap, so if you're wondering what is it.
Basically, I loop through all data hashmap items (to get the A, B and then match if C is inside the other hashmap (map)).
Now the question time
How can I check if an object is contained (exists) or delete it (not by index, but by key)? How can I do this (Example above).
You should define the equals and hashCode method for your class.
Otherwise you fall back to the default implementation which checks for object identity, i.e. if the two references points to the same memory location instead of pointing to two objects containing the same data.
The first problem you have is that Map use key to retrieve value.
Set<Object> set = new HashSet();
Then when you are using Set or Map, your class must override hashcode and equals methods. If the do not do that the Set will not know how to properly compare them, to perform any operation.
This is why when you create a new Object(a,b,c) it set can not find them as it use the default value of hashcode with is not related to type members.
You should have to change the public Map<Object> map = new HashMap<Object>(); field to public Map<String,Foo> map = new HashMap<String,Foo>(); and you should change the name of your class from Object to Foo as 'mre' suggestion.
Foo Class
public class Foo {
private String a;
private String b;
private String c;
public Foo(String a, String b) {
this.a = a;
this.a = b;
this.c = getKey();
}
public String getA() {
return a;
}
public String getB() {
return b;
}
public String getC() {
return c;
}
public String getKey() {
return "" + a + b + "";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((b == null) ? 0 : b.hashCode());
result = prime * result + ((c == null) ? 0 : c.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;
Foo other = (Foo) obj;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
if (b == null) {
if (other.b != null)
return false;
} else if (!b.equals(other.b))
return false;
if (c == null) {
if (other.c != null)
return false;
} else if (!c.equals(other.c))
return false;
return true;
}
}
and you can add objects in map as follows
map.put(new Foo("a", "b").getKey(),new Foo("a", "b"));
now you deleteChest() method will be like
public static void deleteChest() {
Foo foo = null;
for (int i = 0; i < data.size(); i++) {
foo = map.get(new Foo(data.get(i).getA(), data.get(i).getB()).getKey())
if( foo != null) {
map.remove(foo.getKey());
}
}
}
hope this will solve your problem..
First, you code cannot be compiled for several reasons.
You called your class Object. FYI java.lang.Object is a base class for all classes. Since real class Object belongs to package java.lang you do not have to import it and therefore it is always available. I do not understand how compiler can solve this naming collision.
Interface Map has 2 parameters: K for key and V for value. Therefre line
public Map<Object> map = new HashMap<Object>();
cannot be compiled. Change it to
public Map<Object, Object> map = new HashMap<Object, Object>();
Or, better use real parameters instead of Object.
Map interface has method put that accepts 2 parameters. Therefore the following line cannot be compiled too.
map.add(new Object ("a", "b"));
Bottom line if you want to use map that associates groups of string use code like following:
Map<String, String> map = new HashMap<>();
map.put("a", "b");
To remove value by key use:
map.remove("a");
To retrieve value use String v = map.get("a")
To retrieve all values use either map.keySet() or map.entrySet().
The solution that work for me is:
map.remove("key");
Try this
if(map.containsKey(key)){
map.remove(map.get(key));
}

Wants to get an element from 1st to last. But returns last to 1st

In get method, I want to get the element from first element to last. But it returns the list in reversed order (last to first element). How can I solve that problem with this code ?
import java.util.*;
class List {
Customer listPtr;
int index;
public void add(Customer customer) {
Customer temp = customer;
if (listPtr == null) {
listPtr = temp;
index++;
} else {
Customer x = listPtr;
while (x.next != null) {
x = x.next;
}
x.next = temp;
index++;
}
}
public Customer get(int index) {
Customer temp = listPtr;
int size = size();
if (index == 0) {
return listPtr;
} else {
while (size != index) {
size--;
temp = temp.next;
System.out.println(size + "------" + index);
}
return temp;
}
}
public int size() {
int size = 0;
Customer temp = listPtr;
while (temp != null) {
temp = temp.next;
size++;
}
return size;
}
public void printList() {
Customer temp = listPtr;
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
}
}
class DemoList {
public static void main(String args[]) {
List list = new List();
Customer c1 = new Customer("10011", "A");
Customer c2 = new Customer("10012", "B");
Customer c3 = new Customer("10013", "C");
Customer c4 = new Customer("10014", "D");
Customer c5 = new Customer("10015", "E");
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
System.out.println(list.get(1));
//list.printList();
}
}
class Customer {
String id;
String name;
Customer next;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return id + " : " + name;
}
public boolean equals(Object ob) {
Customer c = (Customer) ob;
return this.id.equals(c.id);
}
}
the question is somewhat ambiguous.
it looks like you're asking why .get() isn't returning the expected element?
while (size != index) {
size--;
temp = temp.next;
System.out.println(size + "------" + index);
}
return temp;
appears to be the culprit. your loop counter is decrementing from size() to desired index
while your reference is moving forward through the list.
This means that the value of size bears no real resemblance to what index you're looking at.
I'd use
int i =0;
while(++i <= index && i < size){
temp = temp.next;
}
if (i == index) {
return temp
} else {
//off the end, so throw exception
}
Since this is an assignment, it is not appropriate (or in your interest in the long-term) to give you a solution ...
The basic problem is that your get(i) method is not returning the value a position i.
That should be enough of a Hint to allow you to figure out what it is really doing ... and hence to fix it.
Looks like you are doing something very simple in a very complicated way.
I suggest:
First, remove the 'next' field from Customer.
Then, don't bother writing your own List class. Java has several perfectly good List implementations.
Example:
import java.util.*;
class DemoList {
public static void main(String args[]) {
List<Customer> list = new ArrayList<Customer>();
Customer c1 = new Customer("10011", "A");
Customer c2 = new Customer("10012", "B");
Customer c3 = new Customer("10013", "C");
Customer c4 = new Customer("10014", "D");
Customer c5 = new Customer("10015", "E");
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
//first customer:
System.out.println(list.get(0)); //zero-based
//all customers:
for (Customer c : list) {
System.out.println(c);
}
}
}

Categories