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.
Related
I want to compare a collection (ArrayList) of elements if they are the same type. In the beginning I do not know what type the elements are (generic types), so I decided to use Object type. But I still cannot compare them. The problem is in the function triplesort().The warning is:
Operator '>' cannot be applied to 'java.lang.Object', 'java.lang.Object'. If you have any possible solutions to that problem and you let me know, I would be grateful. <3
Triple.java
import java.util.ArrayList;
public class Triple<T, S, U> {
private T t;
private S s;
private U u;
private ArrayList<Object> array = new ArrayList<Object>();
Triple(T t, S s, U u) {
setT(t);
setS(s);
setU(u);
array.add(this.t);
array.add(this.s);
array.add(this.u);
}
public void setT(T t) {
this.t = t;
}
public void setS(S s) {
this.s = s;
}
public void setU(U u) {
this.u = u;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
public U getThird() {
return u;
}
public String toString() {
return t + "\n" + s + "\n" + u + "\n";
}
public boolean isHomogeneous() {
return t.getClass() == s.getClass() && t.getClass() == u.getClass();
}
public void tripleSort() {
try {
for (int i = 1; i < array.size(); ++i) {
Object key = array.get(i);
int j = i - 1;
while (j > -1 && array.get(i) > key) {
array.set(j + 1, array.get(j));
j--;
}
array.set(j + 1, key);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
There are two main issues with code you've provided:
Relational operators <, <=, >, >= can be used only to compare numeric primitive types. Obviously, you can use it with objects.
To compare reference types you can use Comparator or these objects can implement Comparable interface (i.e. they basically are aware how to compare themselves). But it doesn't make since to compare BigDecimal and Boolean, or String and HashMap, how would you approach that? For that reason, these interfaces are generic and Comparator<T> can't be used with objects of type U.
That said, your Triple<T, S, U> would not be able to do a lot with these objects belonging to different type (definitely you can't sort them).
Hence, if you need a data-carrier holding references of three distinct types, that fine. It's still can be useful, but don't expect from it much.
A Java 16 record fits in this role perfectly well:
public record Triple<T, S, U>(T first, S second, U third) {}
But if you need to able to operate with these values comparing them with one another then consider changing the Triple to hold only elements of type T.
Here's an example of how it might be implemented:
public static class Triple<T> {
private List<T> list = new ArrayList<>(3);
private Comparator<T> comp;
private Triple(T first, T second, T third, Comparator<T> comp) { // no way and no need to invoke this constructor outside the class
this.comp = comp;
Collections.addAll(list, first, second, third);
}
public static <T> Triple<T> getInstance(T first, T second, T third, Comparator<T> comp) {
Triple<T> triple = new Triple<>(first, second, third, comp);
triple.init();
return triple;
}
public void init() {
list.sort(comp);
}
public T getFirst() {
return list.get(0);
}
public T getSecond() {
return list.get(1);
}
public T getThird() {
return list.get(2);
}
public boolean isHomogeneous() {
return comp.compare(getFirst(), getSecond()) == 0
&& comp.compare(getFirst(), getThird()) == 0
&& comp.compare(getSecond(), getThird()) == 0;
}
public String toString() {
return list.stream().map(T::toString).collect(Collectors.joining("\n"));
}
}
Usage example:
Let's consider a Triple storing integer value in Descending order.
public static void main(String[] args) {
Triple<Integer> intTriple = Triple.getInstance(5, 3, 12, Comparator.reverseOrder());
System.out.println(intTriple);
}
Output:
12
5
3
I am trying to compare both strings and float in the compareTo method but I'm not sure what my final value is going to be.
Below is the compareTo method that I have implemented so far:
ObjectClass otherObj = (ObjectClass)o;
float f1 = this.getValue();
float f2 = otherObj.getValue();
int retValue = Float.compare(f1,f2);
String code1 = this.getCode();
String code2 = otherObj.getCode();
int retValue2 = code1.compareTo(code2);
int finalRet = ??
return finalRet;
if the input is
hashMap.put(new ObjectClass ("20030122", 0.019f), "20030122");
hashMap.put(new ObjectClass ("20030123", 0.019f), "20030123");
hashMap.put(new ObjectClass ("20030124", 0.011f), "20030124");
my output should be in this order
"20030123", 0.019f
"20030122", 0.019f
"20030124", 0.011f
In order to allow your class to be comparable you must implement in it interface Comparable
When the comparison should be based on more then single class member. You compare it sequentially when result of previous was equal to zero. By sequence order you specify the final ordering.
class MyObject implements Comparable<MyObject> {
String message;
long value;
#Override
public int compareTo(MyObject that) {
if(that == null) {
return -1;
}
if(this == that) {
return 0;
}
int result = this.message.compareTo(that.message);
if(result == 0) {
result = Long.compare(this.value,that.value);
}
return result;
}
}
The above example will result with
"20030122", 0.019f
"20030123", 0.019f
"20030124", 0.011f
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)
I have developed a garbage collector friendly String cache for my Android game. Its purpose is to handle Strings for ints. I made a silly mistake implementing it but the bug never disclosed itself in desktop. In Android, however, the cache started returning funny Strings at once:
class IntStringCache {
private final Map<IntStringCache.IntCacheKey, String> cachedStrings = new HashMap<IntStringCache.IntCacheKey, String>();
private final IntCacheKey tempIntCacheKey = new IntCacheKey(0);
public String getStringFor(int i) {
tempIntCacheKey.setIntValue(i);
String stringValue = cachedStrings.get(tempIntCacheKey);
if (stringValue == null) {
stringValue = String.valueOf(i);
// ERROR - putting the same object instead of new IntCachKey(i)
cachedStrings.put(tempIntCacheKey, stringValue);
}
return stringValue;
}
public int getSize() {
return cachedStrings.size();
}
private class IntCacheKey {
private int intValue;
private IntCacheKey(int intValue) {
this.intValue = intValue;
}
private void setIntValue(int intValue) {
this.intValue = intValue;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + intValue;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IntCacheKey other = (IntCacheKey) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (intValue != other.intValue)
return false;
return true;
}
private IntStringCache getOuterType() {
return IntStringCache.this;
}
}
And the tests all of which pass:
public class IntStringCacheTest {
private IntStringCache intStringCache = new IntStringCache();
#Test
public void shouldCacheString() {
// given
int i = 1;
// when
String s1 = intStringCache.getStringFor(i);
String s2 = intStringCache.getStringFor(i);
// then
assertThat(s1).isNotNull();
assertThat(s1).isEqualTo(String.valueOf(i));
assertThat(s1).isSameAs(s2);
}
#Test
public void shouldCacheTwoValues() {
// given
int i1 = 1;
int i2 = 2;
int expectedCacheSize = 2;
// when
String s1 = intStringCache.getStringFor(i1);
String s2 = intStringCache.getStringFor(i2);
// then
assertThat(intStringCache.getSize()).isEqualTo(expectedCacheSize);
assertThat(s1).isSameAs(intStringCache.getStringFor(i1));
assertThat(s2).isSameAs(intStringCache.getStringFor(i2));
}
}
Note:
assertThat(String.valueOf(1)).isSameAs(String.valueOf(1));
fails.
The fact that the second test passes is interesting as, with the bug, there should be one key in the map that gets updated. This may be explained with hashCode() that could make the same key go into two different buckets inside HashMap. But how is it possible that the same key (even if in two buckets) returns the same two Stings? It seems that even though there is a bug in the code the HashMap does the job correctly.
My Android Java implementation, on the other hand, returns wrong number Strings with this bug at once.
You should consider replacing this entire class with SparseArray or its Support Library equivalent SparseArrayCompat (if you need it on <3.0 devices) as they are specifically designed to map integers to objects in a memory efficient way.
This question already has answers here:
Java enum reverse look-up best practice
(8 answers)
Closed 9 years ago.
I'm trying to set up my enum so that it has a list of names and retrieve a particular name given that value.
Example:
enum {Vanilla, Chocolate, Strawberry};
Given 0, return Vanilla.
Given 1, return Chocolate.
Given 2, return Strawberry.
I haven't been able to find any methods that come with the Java Enum class to do this out of the box. I'm thinking of writing my own that dumps the values into an array and then use binary search to return them, given a particular number.
Is there something built in however that would be better?
Thanks!
If your id corresponds to the enum item's position, you can use the built-in values() and ordinal()-Methods.
// to enum
int intValue = 0;
CustomEnum item = CustomEnum.values()[intValue];
// to int
CustomEnum item = CustomEnum.SOME_ITEM;
int intValue = item.ordinal();
You have to implement it in the Enum. Like this:
public enum MyEnum {
VANILLA(0), CHOCOLATE(1), STRAWBERRY(2);
private int i;
private MyEnum(int i) {
this.i = i;
}
public static MyEnum getFoodById(int id) trhows IllegalArgumentException {
MyEnum result = null;
switch (id):
case 0: {
result = MyEnum.VANILLA;
break;
}
case 1: {
result = MyEnum.CHOCOLATE;
break;
}
case 2: {
result = MyEnum.STRAWBERRY;
break;
}
default : {
throw new IllegalArgumentException("Invalid id ...");
}
}
return result;
}
You can use EnumMap. You can look at here for solution and example.
You can also do it this way:
public enum IntEnum {
Vanilla(0), Chocolate(1), Strawberry(2);
private int value;
IntEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static IntEnum getEnum(int intValue) {
Integer value = intValue;
if (value == null)
throw new IllegalArgumentException();
for (IntEnum v : values())
if (value.equals(v.getValue()))
return v;
throw new IllegalArgumentException();
}
public static void main(String[] args) {
System.out.println(IntEnum.getEnum(1));
}
}
Enums do allow for built in functions.
public enum Flavor
{
VANILLA("Vanilla"),
CHOCOLATE("Chocolate"),
STRAWBERRY("Strawberry");
private final String desc;
Flavor(String desc)
{
this.desc = desc;
}
public String getDesc()
{
return desc;
}
}
public enum Flavor {
Vanilla, Chocolate, Strawberry
}
Flavor v = Flavor.values()[0];
String name = v.name(); // "Vanilla"
http://docs.oracle.com/javase/6/docs/api/java/lang/Enum.html#name()
Use the values() result:
enum Flavours {Vanilla, Chocolate, Strawberry}
assertTrue(Flavours.Vanilla == Flavours.values()[0]);