I am attempting to remove all the nulls, but if the last key's treeSet is null then it remains there. So I was thinking how to delete the last entry if it is null. Since this is a treeMap I thought that I can obtain the last element by accessing it with tm.lastKey() but that method does not seem to exist. So this question is twofold. First, is there a way to delete all the nulls including the last one and the second is, where is the .lastKey() method?
public class Timing {
private static Map<String, SortedSet> tm = new TreeMap<String, SortedSet>();
public static Map manipulate() {
SortedSet ss = new TreeSet();
ss.add("APPL");
ss.add("VOD");
ss.add("MSFT");
tm.put("2019-09-18",null);
tm.put("2019-09-21",ss);
tm.put("2019-09-22", null);
tm.put("2019-09-20",ss);
tm.put("2019-09-19", null);
tm.put("2019-09-23",null);
return tm;
}
public static void printMap() {
for (String s: tm.keySet()) {
System.out.println(s + ": " + tm.get(s));
}
}
// Will delete all but the last one
public static void deleteNull() {
Set set = tm.entrySet();
Iterator i = set.iterator();
Map.Entry me = (Map.Entry) i.next();
// there is no tm.lastKey()??
while(i.hasNext()) {
if (me.getValue() == null) {
i.remove();
}
me = (Map.Entry) i.next();
}
}
}
To remove all entries with a value of null from your map you can replace the deleteNull method with
tm.values().removeIf(Objects::isNull);
A Java TreeMap does specify a lastKey() method. You can see it in the Java-Doc for TreeMap.
The problem is, you can not access the method because you are hiding the real type of your map to your method. You can see it here:
private static Map<String, SortedSet> tm = new TreeMap<String, SortedSet>();
From this, your method only knows that tm is a Map object and those do not have the lastKey() method. Change Map to TreeMap or do a cast inside your method, then it will work.
Alternative 1:
private static TreeMap<String, SortedSet> tm = new TreeMap<String, SortedSet>();
Alternative 2:
public String lastKey() {
if (tm instanceof TreeMap<?, ?>) {
return ((TreeMap<String, SortedSet>) tm).lastKey();
} else {
// Error!
}
}
The absolute simplest way to do this would be to run check the iterator one more time after the while loop ends, like so:
while(i.hasNext()) {
if (me.getValue() == null) {
i.remove();
}
me = (Map.Entry) i.next();
}
if (me.getValue() == null) {
i.remove();
}
me = (Map.Entry) i.next();
This way you'll catch the last value.
However, you can use the key set similar to how you printed the the map.
Set<String> keySet = tm.keySet();
for(int ndx = 0; ndx < keySet.size(); ndx++){
String key = keySet.get(ndx);
if(tm.get(key) == null){
tm.remove(key);
}
}
Related
I have a method that loops through a map containing a <Key, <List<Pair>>. How would I loop through this and get all results? As this list contains multiple currencies. I don't want the different type of currency amounts to add together. My attempt is below, it seems to not be picking up all the results
Assuming you have a Map which contains all of your data you could do something like this:
Iterator<Entry<Date, List<Pair<BigDecimal, Currency>>>> itr = source.entrySet().iterator();
Now that you have this Iterator, you can convert it to an Element iterator:
Iterator<Element> eItr = new Iterator<Element> {
int index = 0;
Iterator<Entry<Date, List<Pair<BigDecimal, Currency>>>> itr = source.entrySet().iterator();
Entry<Date, List<Pair<BigDecimal, Currency>>> current = itr.hasNext()? itr.next() : null;
#Override
public boolean hasNext() {
return current != null;
}
#Override
public Element next() {
try {
return new Element(current.getKey(), current.getValue().get(index).getFirst(), current.getValue().get(index).getSeccond());
} finally {
index++;
if (index >= current.getValue().size()) {
index = 0;
current = itr.hasNext()? itr.next() : null;
}
}
}
}
Map<Date, List<Pair<BigDecimal, Currency>>> map = ...
map.forEach((date, list) -> {
list.forEach(pair -> {
// business logic here
});
});
This will loop through the map, and in turn loop through every list. It is unclear what you are trying to achieve, but hopefully this will point you in the right direction.
EDIT (without Java 8)
for (Map.Entry<Date, List<Pair<BigDecimal, Currency>>> entry : map.entrySet()) {
Date date = entry.getKey();
List<Pair<BigDecimal, Currency>> list = entry.getValue();
for (Pair<BigDecimal, Currency> pair : list) {
BigDecimal bd = pair.getKey();
Currency currency = pair.getValue();
//business logic here
}
}
It's slightly less elegant (I guess that's a reason to upgrade to Java 8), but functionally equivalent to the first solution (with slight scope/variable name differences). the for (T t : Iterable<T>) syntax was introduced in Java 5 with the Iterable interface, so this should work for practically everyone.
EDIT (If specifically using Iterator)
while (source.hasNext()) {
Map.Entry<Date, List<Pair<BigDecimal, Currency>>> entry = source.next();
Date date = entry.getKey();
List<Pair<BigDecimal, Currency>> list = entry.getValue();
for (Pair<BigDecimal, Currency> pair : list) {
BigDecimal bd = pair.getKey();
Currency currency = pair.getValue();
//business logic here
}
}
In my WebApplication I have to check many incoming query parameters from the requestBody. In order not to write the same code in every method, I want to write a function that returns a boolean. When all required parameters are received and the values of the entrySet are not null the method should return true (otherwise false), i can use the incoming query parameters later on in the programm.
Therefore I pack all incoming parameters into a HashMap. Additionally I put a specific list into the method, which provides the required parameters(keys) for checking.
Example Map of queryParams:
Map queryParams = new HashMap();
queryParams.put("id", "1");
queryParams.put("name", "Jane");
queryParams.put("lastname", "Doe");
Example Array:
String[] keys = {"id", "name", "lastname"};
Last version of method:
public static Boolean checkRequestParams(Request request, String[] keys) {
Map params = (JsonUtil.fromJson(request.body(), HashMap.class));
Iterator it = params.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
for (int i = 0; i < keys.length; i++) {
if (pair.getKey().equals(keys[i])) {
return true;
}
}
The Array provides the keys which are the QueryParams the client sent. No i want to compare them and check if the keys in the Hashmap equals to the given keys in the array and if the values of the keys in the Map are not null.
I have tried many variations. Either I got nullPointerExceptions or I always got a null return.
I might be wrong, but as I understood you want to do validate the following condition:
The HashMap keys must belong to the following list of keywords {"id", "name", "lastname"}.
No value from the HashMap should be equal to null.
You might use something similar to this:
map.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null)
So we iterate over the entrySet and check if entry key belong to the defined set and if value is not null.
Here is a more detailed example:
Set<String> keys = Set.of("id", "name", "lastname");
Map<String,List<Integer>> map = Map.of("id", List.of(1,2,3), "name", List.of(4,5,6));
map.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);
Map<String,List<Integer>> map1 = Map.of("id", List.of(1,2,3), "not in the keys", List.of(4,5,6));
map1.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);
Please note that I am using collections factory methods to create Map,List and Set which has been added to java-9, but stream api is available since java-8.
As for your code, you will always get true, because as soon as there is an entrySet which satisfies the condition the method will return result.
for (int i = 0; i < keys.length; i++) {
if (pair.getKey().equals(keys[i])) {
return true; // one single match found return true.
}
}
You can try to reverse the condition and return false as soon as there is a mismatch.
for (int i = 0; i < keys.length; i++) {
if (!pair.getKey().equals(keys[i]) || pair.getValue() == null) {
return false; // mismatch found, doesn't need to verify
// remaining pairs.
}
}
return true; // all pairs satisfy the condition.
I hope you find this useful.
Just using vanilla Java you could try something like this.
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ValidatorExample {
public boolean checkRequestParams(Map<String, Object> request, List<String> keys) {
return isEqualCollection(request.keySet(), keys)
&& !containsAnyNull(request.values());
}
private boolean isEqualCollection (Collection<?> a,Collection<?> b){
return a.size() == b.size()
&& a.containsAll(b)
&& b.containsAll(a);
}
private boolean containsAnyNull(Collection<?> collection){
return collection.contains(null);
}
public static void main(String[] args) {
ValidatorExample validatorExample = new ValidatorExample();
List<String> keys = Arrays.asList("id", "name", "lastname");
Map<String, Object> parametersOk = new HashMap<>();
parametersOk.put("id", "idValue");
parametersOk.put("name", "nameValue");
parametersOk.put("lastname", "lastnameValue");
// True expected
System.out.println(validatorExample.checkRequestParams(parametersOk, keys));
Map<String, Object> parametersWithInvalidKey = new HashMap<>();
parametersWithInvalidKey.put("id", "id");
parametersWithInvalidKey.put("name", "nameValue");
parametersWithInvalidKey.put("lastname", "lastnameValue");
parametersWithInvalidKey.put("invalidKey", "invalidKey");
// False expected
System.out.println(validatorExample.checkRequestParams(parametersWithInvalidKey, keys));
Map<String, Object> parametersWithNullValue = new HashMap<>();
parametersWithNullValue.put("id", null);
parametersWithNullValue.put("name", "nameValue");
parametersWithNullValue.put("lastname", "lastnameValue");
// False expected
System.out.println(validatorExample.checkRequestParams(parametersWithNullValue, keys));
}
}
But I would recommend you to use a validation framework if your project allows it for a more accurate validation.
Should not return immediately if a match is found as we want to test 'all required' parameters. Try something like:
String[] keys = {"id, "name", "lastname"};
public static Boolean checkRequestParams(Request request, String[] keys) {
Map params = (JsonUtil.fromJson(request.body(), HashMap.class));
for (int i = 0; i < keys.length; i++) {
Iterator it = params.entrySet().iterator();
boolean found = false;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if (pair.getKey().equals(keys[i])) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
You are returning true on the first matching key, whereas you want to check whether all keys are present. Further, your code is incomplete, hence, it is impossible to give full diagnostics.
But anyway, there’s no sense in iterating over map here. Just use
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
for(String key: keys) {
if(params.get(key) == null) return false;
}
return true;
}
This will ensure that each key is present and not mapping to null (as “not mapping to null” already implies being present).
When not considering the possibility of an explicit mapping to null, you could check the presence of all keys as simple as
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
return params.keySet().containsAll(Arrays.asList(keys));
}
Alternatively, you could consider a map invalid if any mapped value is null, even if its key is not one of the mandatory keys. Then, it would be as simple as
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
return params.keySet().containsAll(Arrays.asList(keys))
&& !params.values().contains(null);
}
I currently have a Map of key value pairs in the format of
a.b.c: value1
e.f: value2
g: [
g.h: nested_value1
g.i: nested_value2
]
and I need to 'unflatten' this to a new Map in a nested structure -
a:
b:
c: value1
e:
f: value2
g: [
h: nested_value1
i: nested_value2
]
My current attempt doesn't get very far, and throws a ConcurrentModificationException
private static Map<String, Object> unflatten(Map<String, Object> flattened) {
Map<String, Object> unflattened = new HashMap<>();
for (String key : flattened.keySet()) {
doUnflatten(flattened, unflattened, key, flattened.get(key));
}
return unflattened;
}
private static Map<String, Object> doUnflatten(
Map<String, Object> flattened,
Map<String, Object> unflattened,
String key,
Object value) {
String[] parts = StringUtils.split(key, '.');
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
Object current = flattened.get(part);
if (i == (parts.length - 1)) {
unflattened.put(part, value);
} else if (current == null) {
if ((current = unflattened.get(part)) == null) {
current = new HashMap<>();
}
unflattened.put(part, current);
unflattened = (Map<String, Object>) current;
} else if (current instanceof Map) {
unflattened.put(part, current);
unflattened = (Map<String, Object>) current;
}
}
return unflattened;
}
Am I missing something obvious here? One solution is to use a library like JsonFlattener - the only issue is this would involve converting back and forward between JSON alot.
Edit: Thanks for the pointers - I am half way there, one thing I forgot to mention was it also needs to unflatten a collection of HashMaps
Your error comes because you iterate the key set and then change the map, not through the iterator.
The iterators returned by all of this class's "collection view
methods" are fail-fast: if the map is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove method, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future.
You could get around this by using a new map.
The problem with your implementation is that you are writing the output into the same Map that you use for the input, which causes ConcurrentModificationException.
Implementation becomes straightforward with a separate Map for output:
Map<String,Object> unflattened = new HashMap<>();
for (Map.Entry<String,Object> e : flattened.entrySet()) {
String[] parts = StringUtils.split(e.getKey(), ".");
// Find the map to be used as a destination for put(...)
Map<String,Object> dest = unflattened;
for (int i = 0 ; i != parts.length-1 ; i++) {
Object tmp = dest.get(parts[i]);
if (tmp == null) {
// We did not see this branch yet
Map<String,Object> next = new HashMap<>();
dest.put(parts[i], next);
dest = next;
continue;
}
if (!(temp instanceof Map)) {
throw new IllegalStateException();
}
dest = (Map<String,Object>)temp;
}
// Put the entry into the destination Map<>
dest.put(parts[parts.length-1], e.getValue());
}
Note that the process of "unflattening" may fail when the initial map describes an inconsistent hierarchy, for example, one with a branch and a leaf having the same name:
"a.b.c" -> "x" // OK: "a.b" is a branch
"a.b.d" -> "y" // OK: "a.b" is a branch
"a.b" -> "z" // Error: "a.b" is a leaf
Create a new Map instance for your result instead of attempting to reuse the current one. Also, send in the map value, so it doesn't need to be extracted:
private static Map<String, Object> unflatten(Map<String, Object> flattened) {
Map<String, Object> unflattened = new HashMap<>();
for (String key : flattened.keySet()) {
doUnflatten(unflattened, key, flattened.get(key));
}
return unflattened;
}
This also prevents the original keys from being present in the resulting map.
The above also requires a slight rewrite of the doUnflatten method:
private static void doUnflatten(Map<String, Object> current, String key,
Object originalValue) {
String[] parts = StringUtils.split(key, ".");
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
if (i == (parts.length - 1)) {
current.put(part, originalValue);
return;
}
Map<String, Object> nestedMap = (Map<String, Object>) current.get(part);
if (nestedMap == null) {
nestedMap = new HashMap<>();
current.put(part, nestedMap);
}
current = nestedMap;
}
}
Couple of notes: There's no need to return the map from the method. Divide the loop into two distinct cases: Either the value should be written to the map, or a nested map should be created or retrieved.
The simplest solution is to replace line
for (String key : flattened.keySet()) {
to
for (String key : new ArrayList<>(flattened.keySet())) {
but for large data amount it can be not very effective from performance perspective.
I want to print key with the help of hashmap. Isee solution these method but i find right solutionif(hashmapOption.containsValue(parent.getItemAtPosition(position).toString())).
if this is true than print the key value.
You must iterate all entries and print if containing:
// your map is map = HashMap<String, String>
public void printIfContainsValue(Map mp, String value) {
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
// print if found
if (value.equals(pair.getValue())) {
System.out.println(pair.getKey() + " = " + pair.getValue());
}
it.remove(); // avoids a ConcurrentModificationException
}
}
Or return the Entry and do what you want with it:
// your map is map = HashMap<String, String>
public Map.Entry containsValue(Map mp, String value) {
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
// return if found
if (value.equals(pair.getValue())) {
return pair;
}
it.remove(); // avoids a ConcurrentModificationException
}
return null;
}
NOTE: as pointed by John Skeet you must know that:
that's slow; basically HashMap is designed for lookup by key, not value;
there may be multiple matching values, this methods will only return first found value.
This is what I have tried and somehow I get the feeling that this is not right or this is not the best performing application, so is there a better way to do the searching and fetching the duplicate values from a Map or as a matter of fact any collection. And a better way to traverse through a collection.
public class SearchDuplicates{
public static void main(String[] args) {
Map<Integer, String> directory=new HashMap<Integer, String>();
Map<Integer, String> repeatedEntries=new HashMap<Integer, String>();
// adding data
directory.put(1,"john");
directory.put(2,"michael");
directory.put(3,"mike");
directory.put(4,"anna");
directory.put(5,"julie");
directory.put(6,"simon");
directory.put(7,"tim");
directory.put(8,"ashley");
directory.put(9,"john");
directory.put(10,"michael");
directory.put(11,"mike");
directory.put(12,"anna");
directory.put(13,"julie");
directory.put(14,"simon");
directory.put(15,"tim");
directory.put(16,"ashley");
for(int i=1;i<=directory.size();i++) {
String result=directory.get(i);
for(int j=1;j<=directory.size();j++) {
if(j!=i && result==directory.get(j) &&j<i) {
repeatedEntries.put(j, result);
}
}
System.out.println(result);
}
for(Entry<Integer, String> entry : repeatedEntries.entrySet()) {
System.out.println("repeated "+entry.getValue());
}
}
}
Any help would be appreciated. Thanks in advance
You can use a Set to determine whether entries are duplicate. Also, repeatedEntries might as well be a Set, since the keys are meaningless:
Map<Integer, String> directory=new HashMap<Integer, String>();
Set<String> repeatedEntries=new HashSet<String>();
Set<String> seen = new HashSet<String>();
// ... initialize directory, then:
for(int j=1;j<=directory.size();j++){
String val = directory.get(j);
if (!seen.add(val)) {
// if add failed, then val was already seen
repeatedEntries.add(val);
}
}
At the cost of extra memory, this does the job in linear time (instead of quadratic time of your current algorithm).
EDIT: Here's a version of the loop that doesn't rely on the keys being consecutive integers starting at 1:
for (String val : directory.values()) {
if (!seen.add(val)) {
// if add failed, then val was already seen
repeatedEntries.add(val);
}
}
That will detect duplicate values for any Map, regardless of the keys.
You can use this to found word count
Map<String, Integer> repeatedEntries = new HashMap<String, Integer>();
for (String w : directory.values()) {
Integer n = repeatedEntries.get(w);
n = (n == null) ? 1 : ++n;
repeatedEntries.put(w, n);
}
and this to print the stats
for (Entry<String, Integer> e : repeatedEntries.entrySet()) {
System.out.println(e);
}
List, Vector have a method contains(Object o) which return Boolean value based either this object is exist in collection or not.
You can use Collection.frequency to find all possible duplicates in any collection using
Collections.frequency(list, "a")
Here is a proper example
Most generic method to find
Set<String> uniqueSet = new HashSet<String>(list);
for (String temp : uniqueSet) {
System.out.println(temp + ": " + Collections.frequency(list, temp));
}
References from above link itself