How to override getValueAt for HashSet? - java

I need to extend AbstractTableModel to represent some data in a table. I have a class Car which should represent one item (row) in a table:
public class Car implements Comparable<Car> {
public String make;
public int year;
public double engineVol;
public double maxSpeed;
// ...getters/setters for the fields...
public Car (String make, int year, double engineVol, double maxSpeed) {
this.make = make;
this.year = year;
this.engineVol = engineVol;
this.maxSpeed = maxSpeed;
}
#Override
public boolean equals(Object other) {
if (this == other) return true;
if (other == null || getClass() != other.getClass()) return false;
Car car = (Car) other;
if (year != car.year) return false;
if (Double.compare(car.engineVol, engineVol) != 0) return false;
if (Double.compare(car.maxSpeed, maxSpeed) != 0) return false;
return make.equals(car.make);
}
#Override
public int hashCode() {
int result;
long temp;
result = make.hashCode();
result = 31 * result + year;
temp = Double.doubleToLongBits(engineVol);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxSpeed);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
#Override
public int compareTo(Car other) {
return this.make.compareTo(other.make);
}
}
These Car objects are stored in a HashSet, which resides in the CarTableModel:
public class CarTableModel extends AbstractTableModel {
private static final long serialVersionUID = 7927259757559420606L;
private HashSet<Car> cars;
public CarTableModel(HashSet<Car> cars) {
this.cars = cars;
}
#Override
public int getRowCount() {
return cars.size();
}
#Override
public int getColumnCount() {
return 4;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return null;
}
}
As far as I get it I need to override at least 3 methods in an AbstractTableModel. How do I override getValueAt for a HashSet? What are those rowIndex and columnIndex arguments concerning the HashSet? How are those indeces are applied to the HashSet if we cannot get values from one by an index? Is it possible at all?
P.S. It's not my caprice to use a HashSet here, it's a university assignment, so it has to go this way.

How do I override getValueAt for a HashSet?
Don't use a HashSet. You would typically use an ArrayList so the rows are defined in the order you add them to the List.
For example check out Table Row Model which walks through the process of creating a custom model. It also provide a generic TableModel to make the process simpler if you wish.
It's not my caprice to use a HashSet here, it's a university assignment, so it has to go this way.
Missed that comment. I have no idea why you would be required use a HashSet since there is no direct way to access the data. So it seems to me like you need to iterate through the Set every time a row is required. Not very efficient.

You can try to use LinkedHashSet. But it is unclear how to use columnIndex with Car.
Maybe, ArrayTable from guava will help you.

You'll have to know that even if you think of using a Iterator to get to the nth value of your HashSet, the order is undefined.
Here, from the JavaDoc
It makes no guarantees as to the iteration order of the set; in
particular, it does not guarantee that the order will remain constant
over time.
Though, if you really have to use this collection, here is an implementation of getValueAt
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Optional<Car> tmpCar = cars.stream()
.skip(rowIndex) // Assuming your rows begin with 0
.findFirst();
return tmpCar.isPresent() ? tmpCar : null;
}

So, if is mandatory for you to use HashSet, you can do something like that:
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Car car = null;
int = 0;
for (Car c : cars) {
if (i == rowIndex) {
car = c;
break;
}
i++;
}
if (car == null) // handle this situation with your rules
return "";
return car.get<Field as described in your columns>; //
}
Bear in mind that is not guaranteed the order. Then test it a lot.

Related

How to properly use equals() if comparing an object array index and an object?

According to this answer, roughly, if we had a Classroom object array of student objects, class[index] != student1. I believe this is the mistake I am making in implementing my equals method to compare the array[index] object to another object. I believed the array[index] and the object I am comparing against to be the same.
The code below shows my getNumStudents method in which I try to count the number of times a student id shows up in a class. ID represents brand shoes he or she likes (practice exercise out of lecture). This method is in my classroom object class which implements an interface.
#Override
public int getNumStudents(T anEntry) {
int count = 0;
for (int index = 0; index < numberOfEntries; index++) {
if (roster[index].equals(anEntry)) )
{
counter++;
}
}
return count;
}
My equals method is as such and is implemented in the student class:
public boolean equals(Student student) {
if (this == student)
{
return true;
}
if (student == null)
{
return false;
}
if (this.getID() != student.getID())
{
return false;
}
return true;
}
I don't know if I properly did the hashCode override but here it is (in Student class):
#Override
public int hashCode() {
int result = 17;
result = 31 * result + studentID;
return result;
}
I've narrowed down where the bug is to most likely here:
if (roster[index].equals(anEntry)) )
specifically
roster[index].equals(anEntry))
What should I call or how should I adjust my getNumStudents(T anEntry) method to properly return the number of students with a certain ID (representing a shoe type) within a Classroom object array?
Your equals signature is wrong.
The correct signature of equals method must be as follows.
public boolean equals(Object other)
Then inside the method you should check if it is of comparable type and if you really need it to be of type Student, you have to check for this and return false otherwise.
In your case that would be a minimal change required for your implementation:
public boolean equals(Object other)
{
if (this == other)
{
return true;
}
// This also works if `other` is `null`
if (!(other instanceof Student))
{
return false;
}
// Now we cast it to `Student`
final Student student = (Student) other;
if (this.getID() != student.getID())
{
return false;
}
return true;
}

How to get the index of a specific item in an ArrayList?

I fill up an Array List with some numbers and want to find a specific number that is in the Array List and get its position (the index) in my Array List.
Any example would be great!
for example
ProClon.indexOf(spro.getId(id));
First override equals() method with the specified field. then You can use indexOf.(object)
class A {
int i;
// other fields
public A(int i) {
this.i = i;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
A a = (A) o;
return i == a.i;
}
#Override
public int hashCode() {
return i;
}
}
List<A> list = new ArrayList<>();
list.indexOf(new A(3));
check the api of arrayList. indexOf(Object o); does exactly what you need.
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#indexOf(java.lang.Object)
Just use method indexOf in array
arrayName.indexOf(object)

using Natural order with treeset in java

I am getting an unexpected output for this. Please have a look. I am not able to find the problem. What's wrong with my program? Can anybody explain? I am getting the output
Joe Sue Mike Clare Juliet
Joe Mike Clare Juliet
objects in TreeSets and TreeMaps and with Collections.sort() for Lists, using the Comparable Interface.
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
class Person implements Comparable<Person> {
private String name;
public Person(String name) {
this.name = name;
}
public String toString() {
return name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.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;
final Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
#Override
public int compareTo(Person person) {
int len1 = name.length();
int len2 = person.name.length();
if(len1 > len2) {
return 1;
}
else if(len1 < len2) {
return -1;
}
else {
return 0;
}
}
}
public class App {
public static void main(String[] args) {
List<Person> list = new ArrayList<Person>();
SortedSet<Person> set = new TreeSet<Person>();
//adding Element
addElements(list);
addElements(set);
//sorting element
Collections.sort(list);
//displaying result
showElements(list);
System.out.println();
showElements(set);
}
//adding element methods
private static void addElements(Collection<Person> col) {
col.add(new Person("Joe"));
col.add(new Person("Sue"));
col.add(new Person("Juliet"));
col.add(new Person("Clare"));
col.add(new Person("Mike"));
}
private static void showElements(Collection<Person> col) {
for(Person element: col) {
System.out.println(element);
}
}
}
You are comparing the persons by the length of their names. And the names "Joe" and "Sue" have the same length. So only one of them can occur in the TreeSet. However, this comparison criterion is not consistent with the implementation of equals!
You should place your Person objects into a list, and sort this list with Collections#sort - preferably, with an own Comparator. Also see https://stackoverflow.com/a/21659849
EDIT: Further explaination:
A Set can contain each element only once. And by the way that you specified your compareTo method, you impled that "Sue" and "Joe" are equal (because their names have equal lengths). So they can not both appear in a Set.
Note: They are not really equal, based on the equals method. But the TreeSet uses the compareTo method, and this compareTo method is currently not consistent with equals. So the Set shows a wrong behavior because of your wrong compareTo method.
EDIT: A possible solution:
If the names have equal lengths, you can compare them alphabetically. This way, the compareTo method becomes consistent with equals: It will return 0 if and only if the names are equal.
#Override
public int compareTo(Person person) {
int len1 = name.length();
int len2 = person.name.length();
if(len1 > len2) {
return 1;
}
else if(len1 < len2) {
return -1;
}
else {
return name.compareTo(person.name);
}
}
A SortedSet uses compareTo for evaluation if an element can be added to the Set. Your input contains two names with same length (your comparison criterion), hence one of Joe or Sue must be filtered out (in your case Sue).
The TreeSet documentation talks about having(not mandatory) compareTo implementaion consistent with equals. In your case 'Joe' and 'Sue' are of equal length and as per your compareTo implementation they are same. One workaround would be to compare the hashcode values in compareTo methods if they are of equal length.

Implementation of hashCode and equals in int[] Java

It looks like the hashCode() and equals() for int[] are poorly implemented, or not implemented at all!
(Tested with Android, but I expect it to be true for any Java environment).
In order to get HashSet.contains() working properly, I had to create a wrapper for int[] (plse, don't criticize my coding style, look at the essence):
public class IntArray {
private int[] value;
public IntArray(int[] value) {
this.value = value;
}
#Override
public int hashCode() {
int sum = 0;
// Integer overflows are cheerfully welcome.
for (int elem: value) sum += elem;
return sum;
}
#Override
public boolean equals(Object o) {
if (o == null) return (value==null);
if (value != null) {
if (o instanceof int[])
return compare((int[])o);
if (o instanceof IntArray)
return compare(((IntArray)o).value);
}
return false;
}
protected boolean compare(int[] other) {
int len = value.length;
if (other.length != len) return false;
for (int i=0; i<len ; i++)
if (value[i] != other[i]) return false;
return true;
}
}
Works OK, but I prefer to avoid a custom wrapper or a third-party library. Is there an option?
Since the standard Java Hashtable does not allow an override of the hash code used for keys, you are out of luck and will need to use a wrapper like you did.
keep in mind that your hashCode implementation is very bad, you can use this (Taken from java.util.Arrays in the standard JDK) to get a better hash distrubtion:
public static int hashCode(int a[]) {
if (a == null)
return 0;
int result = 1;
for (int element : a)
result = 31 * result + element;
return result;
}
An alternative is to use a different Hashtable, which can deal with primitives.
one such option is Banana, which is a primitive collections library I created.
After Omry Yadan's message the hashCode function becomes as simple as that!
#Override
public int hashCode() {
return Arrays.hashCode(value);
}
For a RISC CPU, like ARM, It may be more efficient:
#Override
public int hashCode() {
int code = 0;
if (value != null) {
code++;
for (int elem: value)
code = (code<<5) - code + elem;
}
return code;
}
May be there is also a standard function for comparing arrays, in which case equals() can be simplified too?

Sorted List in Java

I need to sort the list in java as below:
List contains collection of objects like this,
List list1 = {obj1, obj2,obj3,.....};
I need the final list which has "lowest value" and "repetition of name should avoid".
Ex:
List list1 = {[Nellai,10],[Gujarath,10],[Delhi,30],[Nellai,5],[Gujarath,15],[Delhi,20]}
After Sorting , I need the list like this :
List list1 = {[Nellai,5],[Gujarath,10],[Delhi,20]};
I have 2 Delhi (30,20) in my list. But I need only one Delhi which has lowest fare (20).
How to do that it in java?
Gnaniyar Zubair
If order doesn't matter, a solution is to use a Map[String, Integer], add an entry each time you find a new town, update the value each time the stored value is less than the stored one and then zip all the pairs into a list.
Almost the same as #Visage answer, but the order is different:
public class NameFare {
private String name;
private int fare;
public String getName() {
return name;
}
public int getFare() {
return fare;
}
#Override public void equals(Object o) {
if (o == this) {
return true;
} else if (o != null) {
if (getName() != null) {
return getName().equals(o.getName());
} else {
return o.getName() == null;
}
}
return false;
}
}
....
public Collection<NameFare> sortAndMerge(Collection<NameFare> toSort) {
ArrayList<NameFare> sorted = new ArrayList<NameFare>(toSort.size());
for (NameFare nf : toSort) {
int idx = sorted.getIndexOf(nf);
if (idx != -1) {
NameFare old = sorted.get(idx);
if (nf.getFare() < old.getFare()) {
sorted.remove(idx);
sorted.add(nf);
}
}
}
Collections.sort(sorted, new Comparator<NameFare>() {
public int compare(NameFare o1, NameFare o2) {
if (o1 == o2) {
return 0;
} else {
if (o1.getName() != null) {
return o1.getName().compareTo(o2.getName());
} else if (o2.getName() != null) {
return o2.getName().compareTo(o1.getName());
} else {
return 0;
}
}
}
});
}
I would do it in two stages.
Firstrly sort the list using a custom comparator.
Secondly, traverse the list and, for duplicate entries (which will now be adjacent to each other, provided you worte your comparator correctly), remove the entries with the higher values.
If you want to avoid duplicates, perhaps a class like TreeSet would be a better choice than List.
I would use an ArrayList like this:
ArrayList<Name> listOne = new ArrayList<Name>();
listOne.add(new Name("Nellai", 10);
listOne.add(new Name("Gujarath", 10);
listOne.add(new Name("Delhi", 30);
listOne.add(new Name("Nellai", 5);
listOne.add(new Name("Delhi", 20);
Collection.sort(listOne);
Then create the Name class
class name implements Comparable
{
private String name;
private int number;
public Name(String name, int number)
{
this.name= name;
this.number= number;
}
public String getName()
{
return this.name;
}
public int getNumber()
{
return this.number;
}
public int compareTo(Object otherName) // must be defined if we are implementing //Comparable interface
{
if(otherName instanceif Name)
{
throw new ClassCastException("Not valid Name object"):
}
Name tempName = (Name)otherName;
// eliminate the duplicates when you sort
if(this.getNumber() >tempName.getNumber())
{
return 1;
}else if (this.getNumber() < tempName.getNumber()){
return -1;
}else{
return 0;
}
}
}
I didn't compiled the code, it's edited here so you should fix the code. And also to figure out how to eliminate the duplicates and print only the lowest one.
You need to sweat too.

Categories