Java Hashmap/Hashtable and numbering - java

the question is simple - I have to implement JTree TreeModel interface which requires that every object has a number. The tree will represent data that are kept in hashmap/hashtable. Keys in that hashmap are client objects and values are arrays of resources (or ArrayLists) so numbering is only a problem at the top level. What would be the easiest way to number keys in Hashmap/Hashtable?

public class IndexedMap<V> extends HashMap<Long, V> {
private AtomicLong index = new AtomicLong();
public void put(V value) {
put(index.getAndIncrement(), value);
}
}
IndexedMap<Object> objects = new IndexedMap<Object>();
objects.put("foo");
objects.put("bar");
// ...
But why don't you just use an ArrayList? It holds objects by an index, exactly what you need.

Sounds like the user-object keys need to be ordered - their "number" would be derived from their spot in the ordering.
Are the keys Comparable? If so, maybe use a TreeMap. If not, I suppose insertion order is your best bet (LinkedHashMap)

Related

Finding the key whose value is the lowest value in a hashmap

I'm trying to come up with an efficient way to return a key in my HashMap that has the lowest value in datastructure. Is there a quick and efficient way to do this besides looping through the entire HashMap?
For example, if I have a hashmap that looks like this:
1: 200
3: 400
5: 1
I want to return the key, 5.
No, you have to loop over all the keys in a HashMap to find the smallest. If this is an important operation, you're better off using a SortedMap, for instance TreeMap, which keeps its elements in sorted order, and then you can simply call firstKey() to find the lowest key.
As others have mentioned HashMap itself does not provide this.
So your options are to either compute it on-demand or pre-compute.
To compute it on-demand, you would iterate the HashMap.entrySet()
Depending on the size of the map, frequency of its change and frequency of requiring the key-with-lowest-value, pre-computing (caching) may be more efficient. Something as follows:
class HashMapWithLowestValueCached<K, V extends Comparable> extends HashMap<K, V> {
V lowestValue;
K lowestValueKey;
void put(K k, V v) {
if (v.compareTo(lowestValue) < 0) {
lowestValue = v;
lowestValueKey = k;
}
super.put(k, v);
}
K lowestValueKey () { return lowestValueKey; }
}
No, there is no way of doing this. You need to iterate over all the elements in the HashMap to find the one with the lowest value.
The reason why we have different kinds of storage is that they support different kinds of operations with different efficiency. HashMap is not designed to retrieve elements efficienctly based on their value. The kind of storage class you need for this will depend on what other operations you need to be able to do quickly. Assuming that you probably also want to be able to retrieve items quickly based on their key, the following might work:
Write a wrapper around your HashMap that keeps track of all the elements being added to it, and remembers which oneis the smallest. This is really only useful if retriving the smalls is the only way you need to access by value.
Store all your data twice - once in a HashMap and once in a data structure that sorts by value - for example, a SortedMap with key and value reversed.
If you find you don't need to retrieve by key, just reverse key and value.
No, there is no quick and efficient way of doing that - you need to loop through the entire hash map. The reason for it is that the keys and values in hash maps do not observe any particular order.
No, because otherwise there would exist a sorting algorithm in O(n log n) (probabilistic, though): add all elements to the hash map, than extract the lowest one by one.
//create hashmap
HashMap<Integer, String> yourHashmap = new HashMap<>();
//add your values here
yourHashmap.put(1,"200");
yourHashmap.put(3,"400");
yourHashmap.put(5,"1");
//then create empty arraylist
ArrayList<Integer> listDuplicates = new ArrayList<Integer>();
//filing the empty arraylist with all id's from duplicateHashmap
for (Map.Entry<Integer, String> entry : yourHashmap.entrySet()) {
listDuplicates.add(entry.getKey());
}
//Ordering the numbers
Collections.sort(listDuplicates);
for (Integer num : listDuplicates) {
int id = num; //entry
String number2 = duplicateHashmap.get(num);//value
System.out.println("lowest value = "+id+" : "+number2);
//breaking here because we've found the lowest value...
break;
}

Implementing search based on 2 fields in a java class

I am trying to present a simplified version of my requirement here for ease of understanding.
I have this class
public class MyClass {
private byte[] data1;
private byte[] data2;
private long hash1; // Hash value for data1
private long hash2; // Hash value for data2
// getter and setters }
Now I need to search between 2 List instances of this class, find how many hash1's match between the 2 instances and for all matches how many corresponding hash2's match. The 2 list will have about 10 million objects of MyClass.
Now I am planning to iterate over first list and search in the second one. Is there a way I can optimize the search by sorting or ordering in any particular way? Should I sort both list or only 1?
Best solution would be to iterate there is no faster solution than this. You can create Hashmap and take advantage that map does not add same key but then it has its own creation overload
sort only second, iterate over first and do binary search in second, sort O(nlogn) and binary search for n item O(nlogn)
or use hashset for second, iterate over first and search in second, O(n)
If you have to check all the elements, I think you should iterate over the first list and have a Hashmap for the second one as said AmitD.
You just have to correctly override equals and hashcode in your MyClass class. Finally, I will recomend you to use basic types as much as possible. For example, for the first list, instead of a list will be better to use a simple array.
Also, at the beginning you could select which of the two lists is the shorter one (if there's a difference in the size) and iterate over that one.
I think you should create a hashmap for one of the lists (say list1) -
Map<Long, MyClass> map = new HashMap<Long, MyClass>(list1.size());//specify the capacity
//populate map like - put(myClass.getHash1(), myClass) : for each element in the list
Now just iterate through the second list (there is no point in sorting both) -
int hash1MatchCount = 0;
int hash2MatchCount = 0;
for(MyClass myClass : list2) {
MyClass mc = map.get(myClass.getHash1());
if(mc != null) {
hash1MatchCount++;
if(myClass.getHash2() == mc.getHash2) {
hash2MatchCount++;
}
}
}
Note: Assuming that there is no problem regarding hash1 being duplicates.

Data structure to hold just keys (not caring about value)

I need to store a list of Strings and need to check if a String exists in the list.
I normally would just use some Map with a key and boolean... i.e.
HashMap map<String,Boolean> = new HashMap<String,Boolean)()
And just do a map.contains(string)
This is sort of the way I have always done these kind of lookups in the past because I know that using a map will be O(1) access.
I know this might be nitpicky and unimportant, but I was just curious if there was some structure that was out there that would save that boolean value. Just seems like a waste of memory because I don't care about the false value because if the key doesn't exist that equates to false.
I was thinking maybe pointing a keyword to null would do what I want, but I was wondering if there was some data structure that sort of did this.
This is what the Set<T> collection is for. The HashSet<T> implementation is O(1) and internally does just what you propose: It's a HashMap<T,V> where the value for each key is the same internal Object instance. That is, the source contains
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
and the value of each entry is set to PRESENT.
Maybe a HashSet<E>?
Or indeed, anything that implements Set<E>, although they don't all have O(1) expected lookup.
HashSet (or) Someother Set interface implementation may get you the functionality you are looking for.
You should use HashSet<E> - "data structure to hold just keys (not caring about value)". Its implementation is based on HashMap<K,V>, where each element is a value, and keys are just Object, exactly what you need.
public class HashSet<E> ... {
...
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<E,Object>();
}
...
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
...
}
Why not use the usual ArrayList<String> it has the contain method and everything else...

Sorting a HashTable by the values (including alphanumeric)

I have a HashTable with alphanumeric values. I want to sort them.
How can I achieve it?
HashTable doesn't preserve the order.
So better Create a List out of it and Sort it.
You need to wrap your types into a class and then implement a Comparator that compares all the types of values (in your term),
class Foo implements Comparator<Foo>{
private int no;
private String alpha;
//+getter/setters
public int compare(Foo f1, Foo f2){
//put your logic here
}
}
Why? You presumably chose HashTable over TreeMap because it had better performance (and no ordering). If you don't want the performance and you do want the ordering, use a TreeMap.
If you don't want to create a new class to hold the key/value relationship and it you are not interested in a TreeMap, then something like the following will also work:
ArrayList<Entry<String,String>> list = new ArrayList<Entry<String,String>>();
list.addAll(map.entrySet());
Collections.sort(list, new Comparator<Entry<String,String>>() {
#Override
public int compare(Entry<String, String> o1, Entry<String, String> o2) {
//your logic here;
}
});
First question - do you really mean sort the values, or do you mean sort the keys?
If you only want to access the sorted values in order once the best way is create a list or array then sort.
For values: Arrays.sort(table.values().toArray()) or Collections.sort(new ArrayList(table.values()))
For keys: Arrays.sort(table.keySet().toArray()) or Collections.sort(new ArrayList(table.keySet()))
For more on these sorting methods: Arrays.sort() or Collections.sort().
If you want to repeatedly use based on sorted keys, you would be better using a TreeMap.
If you repeatedly want to access based on sorted values (rather than keys), then you could always insert in order into a LinkedHashMap, which will keep the ordering.

A Java collection of value pairs? (tuples?)

I like how Java has a Map where you can define the types of each entry in the map, for example <String, Integer>.
What I'm looking for is a type of collection where each element in the collection is a pair of values. Each value in the pair can have its own type (like the String and Integer example above), which is defined at declaration time.
The collection will maintain its given order and will not treat one of the values as a unique key (as in a map).
Essentially I want to be able to define an ARRAY of type <String,Integer> or any other 2 types.
I realize that I can make a class with nothing but the 2 variables in it, but that seems overly verbose.
I also realize that I could use a 2D array, but because of the different types I need to use, I'd have to make them arrays of OBJECT, and then I'd have to cast all the time.
I only need to store pairs in the collection, so I only need two values per entry. Does something like this exist without going the class route? Thanks!
AbstractMap.SimpleEntry
Easy you are looking for this:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
How can you fill it?
java.util.Map.Entry<String,Integer> pair1=new java.util.AbstractMap.SimpleEntry<>("Not Unique key1",1);
java.util.Map.Entry<String,Integer> pair2=new java.util.AbstractMap.SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
This simplifies to:
Entry<String,Integer> pair1=new SimpleEntry<>("Not Unique key1",1);
Entry<String,Integer> pair2=new SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
And, with the help of a createEntry method, can further reduce the verbosity to:
pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));
Since ArrayList isn't final, it can be subclassed to expose an of method (and the aforementioned createEntry method), resulting in the syntactically terse:
TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);
The Pair class is one of those "gimme" generics examples that is easy enough to write on your own. For example, off the top of my head:
public class Pair<L,R> {
private final L left;
private final R right;
public Pair(L left, R right) {
assert left != null;
assert right != null;
this.left = left;
this.right = right;
}
public L getLeft() { return left; }
public R getRight() { return right; }
#Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
#Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
}
And yes, this exists in multiple places on the Net, with varying degrees of completeness and feature. (My example above is intended to be immutable.)
Java 9+
In Java 9, you can simply write: Map.entry(key, value)
to create an immutable pair.
Note: this method does not allow keys or values to be null. If you want to allow null values, for example, you'd want to change this to: Map.entry(key, Optional.ofNullable(value)).
Java 8+
In Java 8, you can use the more general-purpose javafx.util.Pair to create an immutable, serializable pair. This class does allow null keys and null values. (In Java 9, this class is included in the javafx.base module). EDIT: As of Java 11, JavaFX has been decoupled from the JDK, so you'd need the additional maven artifact org.openjfx:javafx-base.
Java 6+
In Java 6 and up, you can use the more verbose AbstractMap.SimpleImmutableEntry for an immutable pair, or AbstractMap.SimpleEntry for a pair whose value can be changed. These classes also allow null keys and null values, and are serializable.
Android
If you're writing for Android, just use Pair.create(key, value) to create an immutable pair.
Apache Commons
Apache Commons Lang provides the helpful Pair.of(key, value) to create an immutable, comparable, serializable pair.
Eclipse Collections
If you're using pairs that contain primitives, Eclipse Collections provides some very efficient primitive pair classes that will avoid all the inefficient auto-boxing and auto-unboxing.
For instance, you could use PrimitiveTuples.pair(int, int) to create an IntIntPair, or PrimitiveTuples.pair(float, long) to create a FloatLongPair.
Hand-rolled implementations
As of Java 16, records have come out of preview status, so you can now do:
public record Pair<K, V>(K key, V value) {
public static <K, V> Pair<K, V> of(K key, V value) {
return new Pair<>(key, value);
}
}
The above implementation will have a big advantage in the future, as it'll allow you to do record deconstruction.
Prior to Java 16, you can achieve the same semantics with Project Lombok:
#Value(staticConstructor = "of")
public class Pair<K, V> {
K key;
V value;
}
or, with the following verbosity (which, unlike the class listed in the accepted answer, guards against NullPointerExceptions, and has a robust hashCode() implementation identical to that of Records1):
import java.util.Objects;
public class Pair<K, V> {
public final K key;
public final V value;
private Pair(K key, V value) {
this.key = key;
this.value = value;
}
public static <K, V> Pair<K, V> of(K key, V value) {
return new Pair<>(key, value);
}
public boolean equals(Object o) {
return o instanceof Pair && Objects.equals(key, ((Pair<?,?>)o).key) && Objects.equals(value, ((Pair<?,?>)o).value);
}
public int hashCode() {
return 31 * Objects.hashCode(key) + Objects.hashCode(value);
}
public String toString() {
return key + "=" + value;
}
}
1 Tested on OpenJDK 17
Map.Entry
These built-in classes are an option, too. Both implement the Map.Entry interface.
AbstractMap.SimpleEntry
AbstractMap.SimpleImmutableEntry
Apache common lang3 has Pair class and few other libraries mentioned in this thread What is the equivalent of the C++ Pair<L,R> in Java?
Example matching the requirement from your original question:
List<Pair<String, Integer>> myPairs = new ArrayList<Pair<String, Integer>>();
myPairs.add(Pair.of("val1", 11));
myPairs.add(Pair.of("val2", 17));
//...
for(Pair<String, Integer> pair : myPairs) {
//following two lines are equivalent... whichever is easier for you...
System.out.println(pair.getLeft() + ": " + pair.getRight());
System.out.println(pair.getKey() + ": " + pair.getValue());
}
To anyone developing for Android, you can use android.util.Pair. :)
What about "Apache Commons Lang 3" Pair class and the relative subclasses ?
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
...
#SuppressWarnings("unchecked")
Pair<String, Integer>[] arr = new ImmutablePair[]{
ImmutablePair.of("A", 1),
ImmutablePair.of("B", 2)};
// both access the 'left' part
String key = arr[0].getKey();
String left = arr[0].getLeft();
// both access the 'right' part
Integer value = arr[0].getValue();
Integer right = arr[0].getRight();
ImmutablePair is a specific subclass that does not allow the values in the pair to be modified, but there are others implementations with different semantic. These are the Maven coordinates, if you need them.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
You could write a generic Pair<A, B> class and use this in an array or list. Yes, you have to write a class, but you can reuse the same class for all types, so you only have to do it once.
Java 14+ edition
You can create a record which implements equals, hashCode, and toString out of the box. Interfaces like Comparable could also be implemented, if needed.
record Pair<A, B>(A first, B second) {}
Records are immutable.
Expanding on the other answers a generic immutable Pair should have a static method to avoid cluttering your code with the call to the constructor:
class Pair<L,R> {
final L left;
final R right;
public Pair(L left, R right) {
this.left = left;
this.right = right;
}
static <L,R> Pair<L,R> of(L left, R right){
return new Pair<L,R>(left, right);
}
}
if you name the static method "of" or "pairOf" the code becomes fluent as you can write either:
list.add(Pair.of(x,y)); // my preference
list.add(pairOf(x,y)); // use with import static x.y.Pair.pairOf
its a real shame that the core java libraries are so sparse on such things that you have to use commons-lang or other 3rd parties to do such basic stuff. yet another reason to upgrade to scala...
The preferred solution as you've described it is a List of Pairs (i.e. List).
To accomplish this you would create a Pair class for use in your collection. This is a useful utility class to add to your code base.
The closest class in the Sun JDK providing functionality similar to a typical Pair class is AbstractMap.SimpleEntry. You could use this class rather than creating your own Pair class, though you would have to live with some awkward restrictions and I think most people would frown on this as not really the intended role of SimpleEntry. For example SimpleEntry has no "setKey()" method and no default constructor, so you may find it too limiting.
Bear in mind that Collections are designed to contain elements of a single type. Related utility interfaces such as Map are not actually Collections (i.e. Map does not implement the Collection interface). A Pair would not implement the Collection interface either but is obviously a useful class in building larger data structures.
I was going to ask if you would not want to just use a List<Pair<T, U>>? but then, of course, the JDK doesn't have a Pair<> class. But a quick Google found one on both Wikipedia, and forums.sun.com. Cheers
Spring has a Pair<S,T> type in the Data Utils package org.springframework.data.util
Pair<String,Integer> pair = Pair.of("Test", 123);
System.out.println(pair.getFirst());
System.out.println(pair.getSecond());
This is based on JavaHelp4u 's code.
Less verbose and shows how to do in one line and how to loop over things.
//======> Imports
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
//======> Single Entry
SimpleEntry<String, String> myEntry = new SimpleEntry<String, String>("ID", "Text");
System.out.println("key: " + myEntry.getKey() + " value:" + myEntry.getValue());
System.out.println();
//======> List of Entries
List<Entry<String,String>> pairList = new ArrayList<>();
//-- Specify manually
Entry<String,String> firstButton = new SimpleEntry<String, String>("Red ", "Way out");
pairList.add(firstButton);
//-- one liner:
pairList.add(new SimpleEntry<String,String>("Gray", "Alternate route")); //Ananomous add.
//-- Iterate over Entry array:
for (Entry<String, String> entr : pairList) {
System.out.println("Button: " + entr.getKey() + " Label: " + entr.getValue());
}
Apache Crunch also has a Pair class:
http://crunch.apache.org/apidocs/0.5.0/org/apache/crunch/Pair.html
I mean, even though there is no Pair class in Java there is something pretty simmilar: Map.Entry
Map.Entry Documentation
This is (simplifying quite a bit) what HashMap , or actually any Map stores.
You can create an instance of Map store your values in it and get the entry set. You will end up with a Set<Map.Entry<K,V>> which effectively is what you want.
So:
public static void main(String []args)
{
HashMap<String, Integer> values = new HashMap<String,Integer>();
values.put("A", 235);//your custom data, the types may be different
//more data insertions....
Set<Map.Entry<String,Integer>> list = values.entrySet();//your list
//do as you may with it
}
just create a class like
class Tuples
{
int x;
int y;
}
then create List of this objects of Tuples
List<Tuples> list = new ArrayList<>();
so you can also implement other new data structures in the same way.
In project Reactor (io.projectreactor:reactor-core) there is advanced support for n-Tuples:
Tuple2<String, Integer> t = Tuples.of("string", 1)
There you can get t.getT1(), t.getT2(), ... Especially with Stream or Flux you can even map the tuple elements:
Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));
What about com.sun.tools.javac.util.Pair?
First Thing on my mind when talking about key/value pairs is the Properties Class where you can save and load items to a stream/file.
You can reuse existing Pair or any such class from "God knows how many libraries already provide such classes". And If you do not want anything from Hans Brende's answer on this question then I don't see any reason for not using 2D Array or List of Object Arrays/ArrayLists used as Pairs/Tuples. The reason for not using Array, you mentioned:
I also realize that I could use a 2D array, but because of the different types I need to use, I'd have to make them arrays of OBJECT, and then I'd have to cast all the time.
Even if you use Pair class from the Accepted Answer, you'll still have to cast the key and value objects. Since you want to store objects of all the types in there. In other words List<Pair> pairs is no different from List<Pair<? extends Object>> pairs which in turn is no different from Object[][2] or List<Object[]> or List<List<Object>>. Because if you write the following code:
List<Pair> pairs = new ArrayList<>();
// logic for populating pairs into list goes here
// then after sometime you need an element
Pair p = pairs.get(whateverIndex);
Object key = p.getKey(); // We don't know type of key, right?
Object value = p.getValue(); // We don't know the exact type here as well
// All sorts of type guessing statemntes go here
GuessedTypeOfKey finallyMyKey = (GuessedTypeOfKey) key;
GuessedTypeOfValue finallyMyValue = (GuessedTypeOfValue) value;
You still have to do the type casting. So I don't find any other reason to not use 2d Object array or List of Object Arrays/ArrayLists used as Pairs/Tuples . Following is code using List and arrays
List<Object[]> simplePairs = new ArrayList<>();
// Add values to pairs
simplePairs.add(new Object[]{1,"One"});
simplePairs.add(new Object[]{"Another Key of Different Type","Value"});
simplePairs.add(new Object[]{"Another Key of Different Type",new AnotherType("Another Value Type")});
// get values
Object[] pair = simplePairs.get(whateverIndex);
Object key = pair[0];
Object value = pair[1];
What you want is a List of some kind of object. I personally do not like using generic Pair classes. They have too many disadvantages:
They are not very expressive. They provide no contextual information besides their type arguments.
They prevent you from using primitive types
You can't apply any constraints on keys or values (besides their
type, of course).
They force you to carry the verbose type parameter declaration in many places (though this is somewhat mitigated by var and <>)
I prefer using ad-hoc classes. While a few years ago, this came with annoying boilerplate, this is no longer the case.
Here is a couple of alternatives that makes the declaration of the class really easy:
Java 14 and above: use a record class
record TypedCount(String type, int count) {}
There, that's it. You get toString() and equals() for free
Before Java 14: use lombok's #Value annotation
#Value
class TypedCount {
String type;
int count;
}
That's also it. Lombok automatically makes the fields private final, constructors, getters, toString() and equals().
While this requires you to add lombok as a dependency, this is only a compile-time dependency that generates the code for you. The lombok library does not need to be in your classpath at runtime.

Categories

Resources