I have this hashtable :
private final Hashtable<Integer,Character> htable = new Hashtable<>();
I am storing some element in the table with indexes that may reach high ranges.
Then when i want to get an item, if it does not exist, i would like the get the first existing one before.
A naive way to do it could be :
int index = given_index;
while(htable.get(index) == null && index >= 0)
index --;
Doing this may compute a big amount of values.
Is there a better strategy, or maybe another sort of table allowing to compute less ?
NavigableMap (as mentioned in comment by user15358848)
Ref: NavigableMap
Generally, implementations should not support null values. If there are implementations that supports null, it will be impossible to check whether the response null was due to absence or an actual value.
lowerEntry
Returns a key-value mapping associated with the greatest key strictly less than the given key, or null if there is no such key.
get value for key
if fetched value is null, then fetch lowerEntry
getOrDefault(key, navigableMap.lowerEntry(index)) will be costly if actual key is present mostly due to additional navigableMap.lowerEntry call
Character value = navigableMap.get(index);
if (value == null) {
value = navigableMap.lowerEntry(index);
}
return value;
floorEntry
Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key.
read using floorEntry
if non-null entry, return value
else return null
Map.Entry<Integer, Character> entry = navigableMap.floorEntry(index);
return null != entry ? entry.getValue() : null;
get the index or the index in front of it with a lambda
htable.keySet().stream().sorted()
.filter(i -> i <= target).max(Integer::compare).orElse(-1);
… where target is the index You are searching
Related
I want to make a histogram by using a HashMap, the key should be the delay, the value the amount of times this delay occurs. I am doubting to use the HashMap replace or the HashMap put function if an already existing delay has an new occurence. I did it by this way:
int delay = (int) (loopcount-packetServed.getArrivalTime());
if(histogramType1.containsKey(delay)) {
histogramType1.replace(delay, histogramType1.get(delay) + 1);
} else {
histogramType1.put(delay, 1);
}
Is this correct? or should I use two times the put function?
There is absolutely no difference in put and replace when there is a current mapping for the wanted key. From replace:
Replaces the entry for the specified key only if it is currently mapped to some value.
This means that if there is already a mapping for the given key, both put and replace will update the map in the same way. Both will also return the previous value associated with the key. However, if there is no mapping for that key, then replace will be a no-op (will do nothing) whereas put will still update the map.
Starting with Java 8, note that you can just use
histogramType1.merge(delay, 1, Integer::sum);
This will take care of every condition. From merge:
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null.
In this case, we are creating the entry delay -> 1 if the entry didn't exist. If it did exist, it is updated by incrementing the value by 1.
In your case, since you first check if the value is contained in the map, using put or replace leads to the same result.
You can use either, based on what is more readable to you.
If you look at the sources you can see the following (this is from update 11 but probably hasn't changed much):
replace:
if ((e = getNode(hash(key), key)) != null) {
V oldValue = e.value;
e.value = value;
afterNodeAccess(e);
return oldValue;
}
put (internal method putVal):
//some code before this to find the node e (similar to getNode(hash(key)))
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null) //onlyIfAbsent is false here
e.value = value;
afterNodeAccess(e);
return oldValue;
}
As you can see, the relevant parts of the code do basically the same thing since onlyIfAbsent is false for put and thus always will replace the value.
You can verify the behavior the others have described, with this:
public class Main {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.replace("a", "1");
System.out.println(map.get("a"));
map.put("a", "1");
System.out.println(map.get("a"));
map.replace("a", "2");
System.out.println(map.get("a"));
}
}
As sparseArray has some more features than hashmap I'm using it but the issue is it does not provide a method which can check if the key is present in it. how can we simply check the key is present it or not, like a map.containsKey(key)like this Map method.
if(sparseArray!!.size()>0) {
sparseArray?.removeAt(sparseArray!!.indexOfKey(id.toInt()))
}
if(sparseArray.size() > 0 && sparseArray.indexOfKey(int) >= 0) {
// Your code...
}
Ref: https://developer.android.com/reference/android/util/SparseArray.html#indexOfKey%28int%29
Returns the index for which keyAt(int) would return the specified key,
or a negative number if the specified key is not mapped.
Check this post :
if(sparseArray.indexOfKey(int) < 0) {
//Item does not exist. Do something relevant
}
You can check this by wether value return by given key is null or not
Consider following answer
Use if(get(key) != null) as a quick replacement for contains().
SparseArrays map integers(key) to Objects(Values). Unlike a normal array of Objects, there can be gaps in the indices.
I ran the following code
public class MapTest {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put(null, null);
System.out.println(map.get(null));
System.out.println(map.containsKey(null));
System.out.println(map.containsValue(null));
}
}
And it gave this output
null
true
true
However, when I remove the line map.put(null, null), map.get(null) still returns null, but map.containsKey(null) & map.containsValue(null) return false. Now, if the value null is not associated with any key, how come it is possible that map.get(null) still returns null?
The Javadoc for the Map interface states that get should return null for any key that does not have a mapping:
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
Note however that some Map implementations may not allow null keys, in which case map.get(null) will throw a NullPointerException. An example of this is the ConcurrentHashMap.
If the map doesn't find the value in the map, then get(object) still returns null.
So for any arbitrary values you will get null as well.
Here's an except of the get() source code of HashMap:
public V get(Object key) {
if (key == null)
return getForNullKey();
...
}
If the key passed is null, it gets that key and returns the value associated to it, else it returns null.
private V getForNullKey() {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
map.get(null) returns null because:
Java Hash Map get Method
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (There can be at most one such mapping.)
A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.
This is possible:
map.put(null, null);
because:
Java Hash Map
This implementation provides all of the optional map operations, and permits null values and the null key.
There is no Strange behavior here. Mapis a interface in java collection framework and HashMap is implementaion.
Simply map is a data structure allows to store key,value pair.
in here you are putting null as key and null as value. your HashMap<String,Integer> accept these value since String and Integers default value is null.
Then your are calling
map.get(null) // argument is a key and return value assign to that key. So you are getting null.
map.containsKey(null)// this method return true if particular key is there. In this case null is your key since return true
map.containsKey(null) // this method return true if there is null as value in your may. This case this is also true.
And the next time your are getting null since map is empty and Integers default value is null. and obviously other two method return false since map is empty.
I'm writing a function to test if a HashMap has null values. The method .values() SHOULD return a collection of just the values, but instead I receive a map with both the keys and values stored inside. This is no good as the purpose of my function is to check if the values are null, but if I return a map with keys AND values then .values().isEmpty() returns false if I have a key stored with no value.
public Map<KEY, List<VALUES>> methodName() {
if (MAPNAME.values().isEmpty()) {
throw new CustomErrorException(ExceptionHandler.getErrorWithDescription(ErrorConstants.ERROR_MSG_01));
} else {
return MAPNAME;
}
}
In the above example, .values() always returns a map containing all the keys and values. My method never throws a CustomErrorException if the HashMap has a key, which is bad since it's supposed to detect if there are no values. Help!
There's no such thing as a Map implementation that has a key stored without a value. All Map implementations either:
throw an exception in put when the value is null
Add an entry with a key and a value of null
A key that maps to null is very different than a key without a value. The key has a value, and that value is null (and that means that the values collection won't be empty, unless the map is empty). A key without a value is a key that's not contained in the map.
Long story short, you probably want to use MAPNAME.values().contains(null) or even just MAPNAME.containsValue(null) to do what you want. Alternatively, if you're checking that every key maps to null, check that by iterating over the .values() collection.
You're returning the map -- MAPNAME, not the values:
return MAPNAME.values();
If you're trying to determine if the map contains any null values, you should iterate over the collection of values and check each one to see if its null.
A map that contains an entry with a null value is not empty.
You're not being very clear about what you want -- your map values are lists -- considering that, there are three ways to have a key map to "no values":
A key mapped to null (then the test is map.values().contains(null) )
A key mapped to an empty list (then the test is map.values().contains(Collections.emptyList()) )
A key mapped to a list full of nulls.
What your method above is doing right now is throwing an exception if the map is truly empty (no keys), and returning the map otherwise.
It is not clear what you want. If you want the method to throw an exception only if the map has no meaningful values (all keys map either to null or to empty lists) then something like this is what you need:
public Map<KEY, List<VALUES>> methodName() {
for( List<VALUES> values : MAPNAME.values() ) // 1
if( null != values ) // 2
for( VALUES value : values ) // 3
if( null != value ) // 4
return MAPNAME;
throw new CustomErrorException(ExceptionHandler.getErrorWithDescription(ErrorConstants.ERROR_MSG_01));
}
This throws an exception in the all reasonably conceivable "empty map" scenarios -- if (1) the map is truly empty, or (2) it contains only null keys, or (3) it only contains only null values or empty lists, or (4) it contains only null values or empty lists or lists of nulls.
(Levels of "emptiness" tests in the text above correspond to the comment labels in the code).
Use the values() method in this way:-
Collection set=MAPNAME.values();
And then use a foreach loop to check if every value is null or not.
I need to be able to sort multiple intermediate result sets and enter them to a file in sorted order. Sort is based on a single column/key value. Each result set record will be list of values (like a record in a table)
The intermediate result sets are got by querying entirely different databases.
The intermediate result sets are already sorted based on some key(or column). They need to be combined and sorted again on the same key(or column) before writing it to a file.
Since these result sets can be massive(order of MBs) this cannot be done in memory.
My Solution broadly :
To use a hash and a random access file . Since the result sets are already sorted, when retrieving the result sets , I will store the sorted column values as keys in a hashmap.The value in the hashmap will be a address in the random access file where every record associated with that column value will be stored.
Any ideas ?
Have a pointer into every set, initially pointing to the first entry
Then choose the next result from the set, that offers the lowest entry
Write this entry to the file and increment the corresponding pointer
This approach has basically no overhead and time is O(n). (it's Merge-Sort, btw)
Edit
To clarify: It's the merge part of merge sort.
If you've got 2 pre-sorted result sets, you should be able to iterate them concurrently while writing the output file. You just need to compare the current row in each set:
Simple example (not ready for copy-and-paste use!):
ResultSet a,b;
//fetch a and b
a.first();
b.first();
while (!a.isAfterLast() || !b.isAfterLast()) {
Integer valueA = null;
Integer valueB = null;
if (a.isAfterLast()) {
writeToFile(b);
b.next();
}
else if (b.isAfterLast()) {
writeToFile(a);
a.next();
} else {
int valueA = a.getInt("SORT_PROPERTY");
int valueB = b.getInt("SORT_PROPERTY");
if (valueA < valueB) {
writeToFile(a);
a.next();
} else {
writeToFile(b);
b.next();
}
}
}
Sounds like you are looking for an implementation of the Balance Line algorithm.