Java map, filter with property values

I have

TreeMap resMap new TreeMap<String, Map<String, String>>(); 

I would like to filter and store only records in which the values ​​contain a known pair, say ('mike' => 'jordan') and avoid the loop as shown below

Is there a filter method in my included libraries apache.commons and google.common (maybe this will do the loop too, but at least it's less verbose

 for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){ if (el.getValue().get("mike").equals("jordan")){ // } } 
+6
source share
5 answers

You can use filters from Guava and the Predicate interface.

 Predicate<T> yourFilter = new Predicate<T>() { public boolean apply(T o) { // your filter } }; 

So a simple example:

 Predicate<Integer> evenFilter = new Predicate<Integer>() { public boolean apply(Integer i) { return (i % 2 == 0); } }; Map<Integer, Integer> map = new HashMap<Integer, Integer>(); Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter); 
+9
source

Instead of forcing your client code to use a filter / loop, create what you need in your class API:

 public class MyClass { private TreeMap resMap new TreeMap<String, Map<String, String>>(); public void filter(String key, String value) { // Some impl here. Either your loop or the guava approach } } 

By the way, if you are using your own loop, think about this:

 for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) { Map.Entry<String, TreeMap<String, String>> entry = i.next(); if (value.equals(entry.getValue().get(key))) { i.remove(); } } 

Changes in the loop:

  • Equal order changed to avoid NPE
  • Using iterator to delete records directly

Even if you don’t have a class, you can easily wrap it in a static method in a utility class, where it can also be easily parameterized to work with any embedded map:

 public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) { // Some impl here } 

Here is the non-guava impl for the static method:

 for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) { Map.Entry<K1, Map<K2, V>> entry = i.next(); if (value.equals(entry.getValue().get(key))) { i.remove(); } } 
+4
source

Take a look at Guava Predicates and Functions .

0
source

Here are two examples. Both print the key based on the correspondence in the value properties.

 private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) { for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet()) if (value.equals(entry.getValue().get(key))) System.out.println(entry.getKey()); } private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) { Predicate<Map<String, String>> keyValueMatch = new Predicate<Map<String, String>>() { @Override public boolean apply(@Nullable Map<String, String> stringStringMap) { return value.equals(stringStringMap.get(key)); } }; Maps.EntryTransformer<String, Map<String, String>, Void> printKeys = new Maps.EntryTransformer<String, Map<String, String>, Void>() { @Override public Void transformEntry(@Nullable String s, @Nullable Map<String, String> stringStringMap) { System.out.println(s); return null; } }; Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys); } public static void main(String... args) { Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>(); printMatchingEntriesUsingALoop(resMap, "first", "mike"); printMatchingEntriesUsingGuava(resMap, "first", "mike"); } 

One uses a loop and one uses Guava.

While the first one works best, you must decide which one is the easiest to understand and save.

Some suggestions from @missingfaktor. You should use your own opinion, but he has well covered some problems.

  • a lot of code duplication.
  • special case processing.
  • More cyclic complexity.
  • More likely to make a mistake as a result of the first three bullets.
  • Hard to execute code.

Imagine that you are a new developer who must support this software. Who would you like to face?

0
source

You can filter the map using java 8 and streams. The first step in this process is to convert to a stream using entrySet().stream() . This gives you Stream<Map.Entry<String, TreeMap<String, String>> . Then you can use filter(...) to filter the list. When you filter, you should return true when the input value should be included in the filter result. After you have filtered the results, you can use foreach to complete the final result.

The end result will look like this:

 resMap.entrySet().stream() .filter(e -> el.getValue().get("mike").equals("jordan")) .foreach(e -> { // Do something with your entry here }); 
0
source

Source: https://habr.com/ru/post/918776/


All Articles