Cant understand why my generic code is not working [duplicate] - java

This question already has answers here:
How can I properly compare two Integers in Java?
(10 answers)
Closed 8 years ago.
Below is a simple implementation of a linked list. I have just added the relevant code.
First, I add some values to the list, 10,990 and 10000. When I am searching for the same values, I get true for key = 10, but false for key = 990 and key = 10000, though it should be true. Also, if I change the second value from 990 to 99 and search for key = 99, this time I am getting a true.
I am not sure about using generic type. I guess I am doing something wrong there. Because if I replace generic type with int, I get the correct behavior. Please suggest.
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> num = new LinkedList<Integer>();
num.add(10);
num.add(990);
num.add(10000);
int key = 10;
System.out.println("Key " + key + " found ?" + num.findValue(key));
key = 990; //also checked for Integer key = 990
System.out.println("Key " + key + " found ?" + num.findValue(key));
key = 10000;
System.out.println("Key " + key + " found ?" + num.findValue(key));
}
}
class LinkedList<T>{
private Node<T> first;
private class Node<T>{
private T data;
private Node<T> next;
public Node(T data){
this.data = data;
this.next = next;
}
}
public void add(T data){
Node<T> nn = new Node<T>(data);
nn.next = first;
first = nn;
}
public boolean findValue(T key){
Node current = first;
while(current != null){
if(current.data == key)
return true;
else
current = current.next;
}
return false;
}
}

The == operator compares two object references to see if they refer to the same object. With Integer values, the JVM will cache Integers from -128 through 127.
From the Integer.valueOf javadocs:
This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
When 10 and 99 are boxed, they result in the same Integer object (respectively) when another 10 and 99 are boxed. However, boxing non-cached Integer objects such as 990 and 10000 will result in different Integer objects each time.
Replace == with the equals method, to compare the key contents, not the key references.
if(current.data != null && current.data.equals(key))

You should be using .equals() instead of == when checking if you've found the value you're looking for:
public boolean findValue(T key){
Node current = first;
while(current != null){
if(current.data != null && current.data.equals(key))
return true;
else
current = current.next;
}
return false;
}
When you declare your LinkedList as a list of Integers, your primitive int is wrapped in an Integer object before it is stored in the node. Thus == doesn't always work because you're not comparing two primitives.

Your problem is that you are using == instead of equals.
It works for int which is a primitive type, but for Integer (object) == returns true only if the two members are the same instance.

In order to be "generic" you should use equals method instead of == operator.

Related

Java - how to get a key object (or entry) stored in HashMap by key?

I'd like to get the "canonical" key object for each key usable to query a map. See here:
Map<UUID, String> map = new HashMap();
UUID a = new UUID("ABC...");
map.put(a, "Tu nejde o zamykání.");
UUID b = new UUID("ABC...");
String string = map.get(b); // This gives that string.
// This is what I am looking for:
UUID againA = map.getEntry(b).key();
boolean thisIsTrue = a == againA;
A HashMap uses equals(), which is the same for multiple unique objects. So I want to get the actual key from the map, which will always be the same, no matter what object was used to query the map.
Is there a way to get the actual key object from the map? I don't see anything in the interface, but perhaps some clever trick I overlooked?
(Iterating all entries or keys doesn't count.)
Is there a way to get the actual key object from the map?
OK, so I am going to make some assumptions about what you mean. After all, you said that your question doesn't need clarification, so the obvious meaning that I can see must be the correct one. Right? :-)
The answer is No. There isn't a way.
Example scenario (not compileable!)
UUID uuid = UUID.fromString("xxxx-yyy-zzz");
UUID uuid2 = UUID.fromString("xxxx-yyy-zzz"); // same string
println(uuid == uuid2); // prints false
println(uuid.equals(true)); // prints true
Map<UUID, String> map = new ...
map.put(uuid, "fred");
println(map.get(uuid)); // prints fred
println(map.get(uuid2)); // prints fred (because uuid.equals(uuid2) is true)
... but, the Map API does not provide a way to find the actual key (in the example above it is uuid) in the map apart from iterating the key or entry sets. And I'm not aware of any existing Map class (standard or 3rd-party) that does provide this1.
However, you could implement your own Map class with an additional method for returning the actual key object. There is no technical reason why you couldn't, though you would have more code to write, test, maintain, etcetera.
But I would add that I agree with Jim Garrison. If you have a scenario where you have UUID objects (with equality-by-value semantics) and you also want to implement equality by identity semantics, then there is probably something wrong with your application's design. The correct approach would be to change the UUID.fromString(...) implementation to always return the same UUID object for the same input string.
1 - This is not to say that such a map implementation doesn't exist. But if it does, you should be able to find it if you look hard enough Note that Questions asking us to find or recommend a library are off-topic!
There is a (relatively) simple way of doing this. I’ve done so in my applications from time to time, when needed ... not for the purpose of == testing, but to reduce the number of identical objects being stored when tens of thousand of objects exist, and are cross-referenced with each other. This significantly reduced my memory usage, and improved performance ... while still using equals() for equality tests.
Just maintain a parallel map for interning the keys.
Map<UUID, UUID> interned_keys = ...
UUID key = ...
if (interned_keys.contains(key))
key = interned_keys.get(key)
Of course, it is far better when the object being stored knows what its own identity is. Then you get the interning basically for free.
class Item {
UUID key;
// ...
}
Map<UUID, Item> map = ...
map.put(item.key, item);
UUID key = ...
key = map.get(key).key; // get interned key
I think there are valid reasons for wanting the actual key. For example, to save memory. Also keep in mind that the actual key may store other objects. For instance, suppose you have a vertex of a graph. The vertex can store the actual data (Say a String, for instance), as well as the incident vertices. A vertex hash value can be dependent only on the data. So to look up a vertex with some data,
D, look up a vertex with data, D,and with with no incident values. Now if you can return the actual vertex in the map you will be able to get the actual incident to the vertex.
It seems to me that many map implementations could easily provide a getEntry method. For example, the HashMap implementation for get is:
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
One could use the getNode method to return an Entry:
public getEntry(Object key){
Node<K,V> e = getNode(hash(key),key);
if(e == null) return null;
return new Entry<>(e.key,e.value);
}
The easiest way is to duplicate the reference to the key in the value using a generic Pair type, like this:
HashMap<UUID,Pair<UUID,String>> myMap = new HashMap<>();
When you put them in the map, you provide the reference to the key to the pair. The cost is one reference per entry.
void add(UUID uuid, String str)
{
myMap.put(uuid,Pair.of(uuid,str));
}
Pair<UUID,String> get(UUID uuid)
{
return myMap.get(uuid);
}
Then getFirst() of the Pair is your key. getSecond() is the value.
Whatever you do, it's going to cost you in either time or space.
Your Pair class will be something like:
public class Pair<A,B>
{
private final A a;
private final B b;
public Pair(A a, B b)
{
this.a = a;
this.b = b;
}
/**
* #return the first argument of the Pair
*/
public A getFirst()
{
return this.a;
}
/**
* #return the second argument of the Pair
*/
public B getSecond()
{
return this.b;
}
/**
* Create a Pair.
*
* #param a The first argument (of type A)
* #param b The second argument (of type B)
*
* #return A Pair of A and B
*/
public static <A,B> Pair<A,B> of(A a, B b)
{
return new Pair<>(a,b);
}
// Don't forget to get your IDE to produce a hashcode()
// and equals() method for you, depending
// on if you allow nulls or not, or DIY.
}
it could help. You can use a for each like below.
Map<String,Object> map = new HashMap<>();
map.put("hello1", new String("Hello"));
map.put("hello2", new String("World"));
map.put("hello3", new String("How"));
map.put("hello4", new String("Are u"));
for(Map.Entry<String,Object> e: map.entrySet()){
System.out.println(e.getKey());
}

Java iteration for possible matches in ArrayList

My question is about iteration and performance. Let's think of following case:
public class Car {
private String name;
private int type;
private int horsePower;
String getKey() {
return type + "_" + horsePower;
}
private final int NUM_OF_CARS = 50000;
public void test() {
List<Car> cars = new ArrayList<Car>(NUM_OF_CARS);
for (int i = 0; i < NUM_OF_CARS; i++) {
Car c = new Car();
if (i == 0 || i == 176 || i == 895 || i == 1500 || i == 4600) {
c.name = "Audi A4 " + i;
c.type = 1;
c.horsePower = 200;
} else {
c.name = "Default";
c.type = 2 + i;
c.horsePower = 201;
}
cars.add(c);
}
// Matches should contain all Audi's since they have same type and horse
// power
long time = SystemClock.currentThreadTimeMillis();
HashMap<String, List<Car>> map = new HashMap<String, List<Car>>();
for (Car c : cars) {
if (map.get(c.getKey()) != null) {
map.get(c.getKey()).add(c);
} else {
List<Car> list = new ArrayList<Car>();
list.add(c);
map.put(c.getKey(), list);
}
}
Iterator<Entry<String, List<Car>>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
if (iterator.next().getValue().size() == 1) {
iterator.remove();
}
}
Log.d("test", String.valueOf((SystemClock.currentThreadTimeMillis() - time)));
}
}
Is this the most efficient way of finding all Audi's here?
This took me 1700 ms
Thanks.
It depends why you're iterating. If you really do need to visit every bottom-level Car, then you don't really have a choice. However, if you're looking for specific matches to the String, then you might consider using a Map.
Why don't you try (Map):
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Basically it's a collection of Hashmaps:
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Here's an example:
Map<String, List<Car>> map = new HashMap<String, List<Car>>();
If you want to find a String you should use HashMap. Otherwise you cannot avoid that type of iterations as far as i have in mind.
Use Hashing collections: HashSet that uses Object.hashCode() and Object.equals() to optimize search. How?
You must define your implementation of MyClass.hashCode() and equals(). hashCode() gives an integer representation of your object (you can do what you want here, but do it in a way where two different objects have different values)
HashSet will then do a modulo on your result ex: if the HashSet size is 5000 it will do a modulo 5000 and it will find the index where to put your object ex: if your hashCode() returns 10252, then 10252 % 5000 = 252. And your object will be put in an array with the index 252.
Finally, when you will ask (do I have an instance of "BMW x6", the object you ask for will have its hashCode() method called, which will return 10252 again. And HashSet will only search if it has an object in the 252 index.
If ever two objects give the same hashCode, then they will be compared through the equals() method.
I hope my explanations were clear. In short implement hashCode and equals() and try making the implementation of hashCode() optimized so you will gain time when filling your HashSet
You will probably also be interested in HashMap which stores keys and values where keys use the hashing mechanism: so you can find an object by its key

More efficient way of iterating through on array list

My program takes in thousands of PL/SQL functions, procedures and views, saves them as objects and then adds them to an array list. My array list stores objects with the following format:
ArrayList<PLSQLItemStore> storedList = new ArrayList<>();
storedList.add(new PLSQLItemStore(String, String, String, Long ));
storedList.add(new PLSQLItemStore(Name, Type, FileName, DatelastModified));
What I wanted to do is remove duplicate objects from the array-list based on their Name. The older object would be removed based on its dateLastModified variable. The approach i took was to have an outer loop and an inner loop with each object comparing themselves to every other object and then changing the name to "remove" if it was considered to be older. The program then does one final pass backwards through the array-list removing any objects whose name is set as "remove". While this works fine it seems extremely inefficient. 1000 objects will mean 1,000,000 passes need to be made. I was wondering if someone could help me make it more efficient? Thanks.
Sample Input:
storedList.add(new PLSQLItemStore("a", "function", "players.sql", 1234));
storedList.add(new PLSQLItemStore("a", "function", "team.sql", 2345));
storedList.add(new PLSQLItemStore("b", "function", "toon.sql", 1111));
storedList.add(new PLSQLItemStore("c", "function", "toon.sql", 2222));
storedList.add(new PLSQLItemStore("c", "function", "toon.sql", 1243));
storedList.add(new PLSQLItemStore("d", "function", "toon.sql", 3333));
ArrayList Iterator:
for(int i = 0; i < storedList.size();i++)
{
for(int k = 0; k < storedList.size();k++)
{
if (storedList.get(i).getName().equalsIgnoreCase("remove"))
{
System.out.println("This was already removed");
break;
}
if (storedList.get(i).getName().equalsIgnoreCase(storedList.get(k).getName()) && // checks to see if it is valid to be removed
!storedList.get(k).getName().equalsIgnoreCase("remove") &&
i != k )
{
if(storedList.get(i).getLastModified() >= storedList.get(k).getLastModified())
{
storedList.get(k).setName("remove");
System.out.println("Set To Remove");
}
else
{
System.out.println("Not Older");
}
}
}
}
Final Pass to remove Objects:
System.out.println("size: " + storedList.size());
for (int i= storedList.size() - 1; i >= 0; i--)
{
if (storedList.get(i).getName().equalsIgnoreCase("remove"))
{
System.out.println("removed: " + storedList.get(i).getName());
storedList.remove(i);
}
}
System.out.println("size: " + storedList.size());
You need to make PLSQLItemStore implement hashCode and equals methods and then you can use Set to remove the duplicates.
public class PLSQLItemStore {
private String name;
#Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + (this.name != null ? this.name.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PLSQLItemStore other = (PLSQLItemStore) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
}
And then just do Set<PLSQLItemStore> withoutDups = new HashSet<>(storedList);
P.S. equals and hashCode are generated by NetBeans IDE.
Put them in a Guava ArrayListMultimap<String,PLSQLItemStore>.
Add each PLSQLItemStore using name as the key.
When you're done adding, loop through the multimap, sort each List with a Comparator<PLSQLItemStore> which sorts by dateLastModified, and pull out the last entry of each List - it will be the latest PLSQLItemStore.
Put these entries in another Map<String,PLSQLItemStore> (or List<PLSQLItemStore>, if you no longer care about the name) and throw away the ArrayListMultimap.
Building off of Petr Mensik's answer, you should implement equals and hashCode. From there, you can put items into the map. If you come across a duplicate, you can decide then what to do:
Map<String, PLSQLItemStore> storeMap = new HashMap<String, PLSQLItemStore>();
for(PLSQLItemStore currentStore : storedList) {
// See if an item exists in the map with this name
PLSQLItemStore buffStore = storeMap.get(currentStore.getName();
// If this value was never in the map, put it in the map and move on
if(buffStore == null) {
storeMap.put(currentStore.getName(), currentStore);
continue;
}
// If we've gotten here, then something is in buffStore.
// If buffStore is newer, put it in the map. Otherwise, do nothing
// (this might be backwards -- I didn't quite follow your logic.
// Feel free to correct me
if(buffStore.getLastModified() > currentStore.getLastModified())
storeMap.put(currentStore.getName(), currentStore);
}
Your map is dup-free. Because Map is a Collection, you can iterate through it later in your code:
for(PLSQLItemStore currentStore : storeMap) {
// Do whatever you want with your items
}

Using String as BST key value

I have a binary search tree which stores objects. For inserting objects to it I am using Int value as a key. I get that value by calling method form the object like this:
public class Tree
{
// The root node of the tree which is null;
private Node root;
private double largest;
private Node insert (Node tree, Element d)
{
if (tree == null) return new Node(d);
else if (d.getPlaceInTable() < tree.data.getPlaceInTable()) tree.left = insert (tree.left, d);
else if (d.getPlaceInTable() > tree.data.getPlaceInTable()) tree.right = insert (tree.right, d);
return tree;
}
public void insert (Element d)
{
root = insert (root, d);
}
But what if I want to use Elements name as a key value which is string? How can I do it? Should I use compareTo() method? I know how to compare string1.compareTo(string2) but I really don' have any idea how I can use it in this case. If you have any suggestions, I really appreciate that.
Yes, String implements Comparable, so you can do
d.getName().compareTo(tree.data.getName()) < 0 for the left node and
d.getName().compareTo(tree.data.getName()) >= 0 for the right node
Also note, that in your original code you do not insert anything in your tree when values are equal.

Mark an empty space into an array without using null

I am extending AbstractMap and I want to implement my own hash-map using two parallel arrays:
K[] keys;
V[] values;
Suppose I want to store null values as well, how could I initialize these two arrays so that I can differentiate between a space in the array where I could place some new key-value pairs and a space where I am storing a null?
Might I suggest not using two arrays, and instead do something along the lines of:
class Node {
K key;
V value;
}
Node[] nodes;
Then a non-entry is an element in nodes that is equal to null.
If the values can be null but the keys cannot be null then having a null key would mean that there is no key.
If the key can also be null you can use a parallel array of booleans to store whether each space is taken or not.
K[] keys;
V[] values;
boolean[] hasValue;
Not quite sure the details of your question, but you could always have some special object for your "blank".
private static final Object BLANK = new Object();
Then if the item in the array == BLANK, then consider it to be an empty slot.
Since there can only be one null key, you can simply have a special reference value (not in the array) that holds the value of the object mapped from this null key (and possibly a boolean indicating if this value has been set). Unfortunately this will probably complicate iteration.
E.g.
private boolean isNullMapped = false;
private V nullValue = null;
public put(K key, V value)
{
if (key == null) { nullValue = value; }
...
}
Alternatively, you can wrap all keys in a wrapper object (supposing you still want to use parallel arrays instead of entries), and if the value contained in this wrapper object is null, then it represents the null key.
E.g.
private static class KeyWrapper<K>
{
public K key;
}
Lastly, as a question for consideration, if you are not having entries in your arrays, but instead are directly holding arrays of K and V, then how are you accounting for different keys that happen to share the same hash code? The java.util implementation has arrays of entries that also act as linked lists to account for this possibility (and incidentally, the null key is always mapped to array index 0).
Storing a null value is not a problem in your scenario. So long as keys[n] != null, just return values[n] whether values[n] is null or not.
Remember that you are not being asked to key on n but objects of type K so every access of the Map will require a search through keys to find the key they are looking for.
However, if you want to allow the storage of a value against a null key then using something like private static final Object NULL_KEY = "NULL" would probably do the trick as the other suggestions point out.
private static final Object NULL_KEY = "NULL";
K[] keys;
V[] values;
private int find(K key) {
for (int i = 0; i < keys.length; i++) {
if (keys[i] == key) {
return i;
}
}
return -1;
}
public V put(K key, V value) {
V old = null;
if (key != null) {
int i = find(key);
if (i >= 0) {
old = values[i];
values[i] = value;
} else {
// ...
}
} else {
return put((K) NULL_KEY, value);
}
return old;
}
public V get(K key) {
if (key != null) {
int i = find(key);
if (i >= 0) {
return values[i];
}
return null;
} else {
return (get((K) NULL_KEY));
}
}
In the java.util implementation a special object representing null is used.

Categories

Resources