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());
}
}
Related
I have a 2d array (int[][]) that represents an area. The integers in each point stand for the value of the same.
The objective is to pick N points in the 2d array so that the sum of their values is the maximum possible. There's the added difficulty of not being able to pick 2 points that stand together, so if you pick one then the 8 spaces arround are banned.
Here's an example for a given map with N=5
Here's how I'm planning to structure it:
public static int[][] getBestPoints(int[][] matrix, int N) {
int[][] bestPoints = []; //the best option picked from the candidates
Map<Int,int[][]> candidates = new HashMap<Int, int[]>{};
//candidates is a map that stores the possition of N elements and the
//total sum of their represented values
//Here there'd be a loop section that searchs for all the best
//combinations and stores them in the var candidates
return bestPoints; //solution for the example picture {{1,3},{1,5},{2,1},{4,2},{5,4}}
}
Any ideas on where to start? Thanks in advance!
Each cell in these matrices could be stored in a class like this:
import java.util.Comparator;
public class Cell {
private int row;
private int column;
private Integer value;
private Integer cost;
public static final Comparator<Cell> SUM_COMPARATOR = (Cell c1, Cell c2) -> c1.getSum().compareTo(c2.getSum());
#Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + this.row;
hash = 71 * hash + this.column;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Cell other = (Cell) obj;
if (this.row != other.row) {
return false;
}
if (this.column != other.column) {
return false;
}
return true;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return column;
}
public void setColumn(int column) {
this.column = column;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public Integer getCost() {
return cost;
}
public void setCost(Integer cost) {
this.cost = cost;
}
public Integer getSum() {
return cost+value;
}
}
The above Cell class stores both cost and value, and a List then contains the information of both matrices. Use Collections.sort() (and Collections.reverse()) to sort them using the SUM_COMPARATOR implemented in class Cell, which compares the sum of cost and value. Iterate the sorted elements and compare them for distance check like this:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
private static final int NUMBER_OF_CELLS_AROUND_EXCLUDED = 1;
public static void main(String[] args){
List<Cell> cells = new ArrayList<>();
// load prices and values in each Cell instance here...
// and sort them
Collections.sort(cells, Cell.SUM_COMPARATOR);
Collections.reverse(cells);
// then iterate both lists, which contain the
List<Cell> chosen = new ArrayList<>();
for (Cell cell : cells){
if (notTooClose(cell, chosen.get((chosen.size()-1)))){
chosen.add(cell);
}
if (chosen.size() == 5)
break;
}
}
private static boolean notTooClose(Cell cellA, Cell cellB){
int rowDist = Math.abs(cellA.getRow()-cellB.getRow());
int colDist = Math.abs(cellA.getColumn()-cellB.getColumn());
return rowDist > NUMBER_OF_CELLS_AROUND_EXCLUDED &&
colDist > NUMBER_OF_CELLS_AROUND_EXCLUDED;
}
}
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;
}
}
I am wondering if I am writing this equals method correctly. My program keeps printing out "equal" even though the two objects Item and otherObject are not equal. I have three equals methods, and none seem to work right when run one at a time. The three equals methods are located right after each other for reference. My main is at the end.
import static java.lang.System.*;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Scanner;
import java.math.*;
public class Item {
DecimalFormat df = new DecimalFormat("#.00");
//the properties of an Item
static double cash=59.00;
static double sum=0.00;
private int priority;
private String name;
private double price;
static boolean value= false;
//default constructer
public Item() {
priority = -1; //fill with default values
price = 0.00;
name = "No name yet";
}
public Item(int priority, String name, double price) {//constructor with all 3 arguments
this.priority = priority;
this.name = name;
this.price = price;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
//priority must be between 1 and 7
if (priority > 0 && priority <= 7) {
this.priority = priority;
} else {
System.err.println("Error, enter 1 through 7");
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
//price between 0 and 100 inclusive
if (price >= 0.00) {
if (price <= 100.00) {
this.price = price;
cash = cash-=price;
sum=sum+=price;
} else {
System.err.println("Error: price to high");
}
} else {
System.err.println("Error: price to low");
}
}
public boolean equals(Item otherObject) {
return this.name.equals(otherObject.name);
}
/*public boolean equals(Item otherObject) {
if(this.getPriority()==(otherObject.getPriority()));
return true;
} */
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + priority;
return result;
}
/*#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Item))
return false;
Item other = (Item) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (priority != other.priority)
return false;
return true;
}*/
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Item [Price= ").append(getPrice()).append(", ");
if (getName() != null) {
builder.append("Name= ").append(getName()).append(", ");
}
builder.append("Priority= ").append(getPriority()).append("]");
return builder.toString();
}
public static void main (String[] args) {
Item[] list = new Item[2];
Scanner keyboard = new Scanner(System.in);
for (int i = 1; i <= list.length; i++) {
if(cash==59)
{
System.out.println("You have 59 dollars");
}
Item otherObject=new Item();
Item anItem = new Item(); // new item object created 7 times
System.out.println("Enter an item you want to add to your list " + i);
anItem.setName(keyboard.next());
System.out.println("Enter a price " + i);
anItem.setPrice(keyboard.nextDouble());
System.out.println("Enter the priority of the item " + i);
anItem.setPriority(keyboard.nextInt());
list[i-1] = anItem;
System.out.println("Cash left "+cash);
System.out.println("Sum of Items "+sum);
System.out.println(Arrays.toString(list));
if (anItem.equals(otherObject)); //--------------- This is printing out each time. Is it comparing default constructors?
{System.out.println("\nequal");}
}
if(sum>59)
{System.err.println("Error, you ran out of money\t\t");
}
// int a;
//int b;
//a=list[0].getPriority();
// b=list[1].getPriority();
//System.out.println(a +" here");
// System.out.println(b +" here");
//final int[] arraySort = { a, b,};
Item temp;
for (int i = 0; i < list.length; i++) {
//min = i;
for (int j = 1; j < (list.length - i); j++) {
if (list[j-1].getPriority() > list[j].getPriority()) {
temp = list[j - 1];
list[j - 1] = list[j];
list[j] = temp;
}
} //min = j;
System.out.println(list[i]);
}
} //main
}// class Item
if("foo".equals("bar"));
{System.out.println("\nequal");}
this prints equal too!
You end the if statement too early, so the next statement is always executed!
You need to remove the ; after the the if
if (anItem.equals(otherObject))
{System.out.println("\nequal");}
If you are looking to override Object#equals(Object), your method signature needs to be
public boolean equals(Object [some identifer])
otherwise you are overloading the method.
Simple trick is to annotate methods that are meant to be overriden with #Override. Any decent IDE will tell you if that method isn't overriding anything.
Otherwise, it doesn't seem like you've set the name of otherObject to that of anItem.name and therefore
this.name.equals(otherObject.name)
will return false.
I think your equals method should be:
public boolean equals(Item otherObject) {
return this.name.equals(otherObject.getName());
}
Simple because name field is private.
This is basically what I'm trying to do:
enum Animal { CAT, FISH }
enum color { RED, GREEN }
int weight = 10
int IQ = 200
AnimalPrice.put((Animal.CAT, Color.GREEN, weight,IQ) , 5)
i.e. the price of a green cat that weights 10 pounds and has 200 iq is 5 dollars.
Is there a way to do this in java? I only got as far as using lists of integer as keys, but nothing about using enum types
There are 2 ways I would consider doing:
1 create the keys as the string concatanation of those 4 values
String key = Animal.CAT + '_' + Color.GREEN + '_' + weight + '_' + IQ;
2 create an object made up of those values and create a custom equals and hashCode method
public class AnimalPriceKey {
private Animal animal;
private Color color;
private int weight;
private int iq;
public AnimalPriceKey(Animal animal, Color color, int weight, int iq) {
this.animal = animal;
this.color = color;
this.weight = weight;
this.iq = iq;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((animal == null) ? 0 : animal.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + iq;
result = prime * result + weight;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AnimalPriceKey other = (AnimalPriceKey) obj;
if (animal != other.animal)
return false;
if (color != other.color)
return false;
if (iq != other.iq)
return false;
if (weight != other.weight)
return false;
return true;
}
}
I would favor the second approach as it's much more robust and future proof.
Use example:
Map<AnimalPriceKey, Integer> animalPrices = new HashMap<AnimalPriceKey, Integer>();
animalPrices.put(new AnimalPriceKey(Animal.CAT, Color.GREEN, 10, 200), 5);
This post is the continuation of my previous post. Now I have a code that I'd like to compile. The only difference is that now I'm using lists of my own class List<Row> instead of List<Integer[]>. In particular look at hashCode in Row, because it provides a compilation error.
public class Row {
private String key;
private Integer[] values;
public Row(String k,Integer[] v) {
this.key = k;
this.values = v;
}
public String getKey() {
return this.key;
}
public Integer[] getValues() {
return this.values;
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Row at this point
Row row = (Row)obj;
return ((key == row.key) && (values == row.values));
}
#Override
public int hashCode () { // HERE I HAVE A PROBLEM. DON'T KNOW HOW TO IMPLEMENT IT
return this.key;
}
}
public class Test {
public static void main(String[] args) {
List<Row> allRows = new ArrayList<Row>();
allRows.add(new Row("0",new Integer[]{1,2,3}));
allRows.add(new Row("0",new Integer[]{1,2,2}));
allRows.add(new Row("1",new Integer[]{1,2,3}));
allRows.add(new Row("2",new Integer[]{1,1,1}));
allRows.add(new Row("2",new Integer[]{1,1,1}));
List<Row> selectedRows = new ArrayList<Row>();
selectedRows.add(new Row("0",new Integer[]{1,2,3}));
selectedRows.add(new Row("2",new Integer[]{1,1,1}));
System.out.println(allRows);
System.out.println(selectedRows);
List<Row> refreshedRows = refreshRows(allRows,selectedRows);
System.out.println(refreshedRows);
}
private static List<Row> refreshRows(List<Row> allRows,List<Row> selectedRows) {
Set<Row> set1 = new HashSet<Row>();
Iterator<Row> it = allRows.iterator();
while(it.hasNext()) {
Row curr = it.next();
if (!set1.add(curr) && selectedRows.contains(curr)) {
it.remove();
}
}
return allRows;
}
}
The result, i.e. refreshedArray, should be equal to:
key = "0", values = {1,2,3}
key = "0", values = {1,2,2};
key = "1", values = {1,2,3};
key = "2", values = {1,1,1};
Try with the following. Despite minor changes, most of the code is generated by Netbeans IDE 7.0:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Row other = (Row) obj;
if ((this.key == null) ? (other.key != null) : !this.key.equals(other.key)) {
return false;
}
if (!java.util.Arrays.deepEquals(this.values, other.values)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 79 * hash + (this.key != null ? this.key.hashCode() : 0);
hash = 79 * hash + java.util.Arrays.deepHashCode(this.values);
return hash;
}
Look at the signature for hashcode(). It returns a primitive integer. You are returning key which is of type String. Try something like this:
#Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + key.hashCode();
//hash = hash * 31 + otherFields.hashCode() etc
return hash;
}
which your IDE can even generate for you. You should probably read up on hashcodes. Your equals method looks wrong too. What is meant by comparing the two Integer arrays for equality?