“What you stay focused on will grow.”
― Roy T. Bennett
Contents
1. Introduction
Having explored HashMap in several previous articles (here and here), let us now learn how to search and sort a HashMap by key as well as value.
2. Finding Keys and Values in HashMap
Finding a key in a HashMap is quite simple. The HashMap API provides containsKey() method which tells you whether the key exists.
Map<String,Integer> namefreq = new HashMap<>();
namefreq.put("Petra", 14);
namefreq.put("Mario", 11);
namefreq.put("Kasandra", 23);
namefreq.put("Charity", 18);
namefreq.put("Minerva", 5);
if ( namefreq.containsKey("Charity") ) {
    // found match
}
Finding a value is also easy given the method containsValue().
if ( namefreq.containsValue(10) ) {
    // found value
}
Pretty simple, right? Well, what if you need to find not a particular value but search for a general expression, such as names starting with say “A”. Gets a bit more involved.
3. Loading CSV into HashMap
The following search and sort examples make use of a name frequency table which is loaded from CSV using the following code. It streams lines from a CSV file, splits the line into fields, selects values for the “CA” state and stores the value as a Map of (year => count). (The data is from US Census Bureau which publishes name frequency counts for each year.)
The code creates a multi-HashMap with the structure:
(name => ((year => count),
          (year => count)),
...
Pattern pattern = Pattern.compile(",");
String csvFile = "StateNames.csv";
try (BufferedReader in = new BufferedReader(new FileReader(csvFile));){
    Map<String,Map<Integer,Integer>> namefreq = in
	.lines()
	.skip(1)
	.map(x -> pattern.split(x))
	.filter(x -> x[4].equals("CA"))
	.collect(HashMap::new, (map, x) ->
		 map.compute(x[1], (k, v) -> {
			 if ( v == null )
			     v = new HashMap<Integer,Integer>();
			 v.put(Integer.parseInt(x[2]),
			       Integer.parseInt(x[5]));
			 return v;
		     }),
		 Map::putAll);
}
Here is a snippet of the sample data being loaded.
Id,Name,Year,Gender,State,Count 1,Mary,1910,F,AK,14 2,Annie,1910,F,AK,12 3,Anna,1910,F,AK,10 4,Margaret,1910,F,AK,8 5,Helen,1910,F,AK,7 6,Elsie,1910,F,AK,6 7,Lucy,1910,F,AK,6 8,Dorothy,1910,F,AK,5 9,Mary,1911,F,AK,12 10,Margaret,1911,F,AK,7
4. Search Key in HashMap
The following code searches for a key ending with “x” and prints the matches.
namefreq
    .entrySet()
    .stream()
    .filter(e -> e.getKey().endsWith("x"))
    .forEach(e -> {
	    System.out.println(e.getKey() + " :");
	    e.getValue().forEach((kk, vv) -> {
		    System.out.println("  " + kk + " => " + vv);
		});
	});
// prints:
Rex :
 1959 => 86
Margaux :
 2003 => 8
Maxx :
 2010 => 28
5. Search Value in HashMap
Let us now search for a value in the HashMap using the same method. Before we do that, let us total the names for each year and store it under the key 0 for each name. Something like this:
Elza : 0 => 10 1993 => 5 2014 => 5 ...
We compute the total value with the following code. It computes a total of the existing mappings of (year => count) and stores it under key 0.
namefreq
    .entrySet()
    .stream()
    .forEach(e -> {
	    Map<Integer,Integer> v = e.getValue();
	    int tot = v
		.entrySet()
		.stream()
		.reduce(0, (x, ee) -> x + ee.getValue(),
			(x, y) -> x+y);
	    v.put(0, tot);
	});
Let us now search the HashMap for names occurring more than 1000 times.
namefreq
    .entrySet()
    .stream()
    .filter(e -> e.getValue().getOrDefault(0, 0) > 1000)
    .forEach(e ->
	     System.out.println(e.getKey()+" : "+e.getValue().get(0)));
// prints:
...
Solomon : 1967
Javier : 28472
Esther : 16974
Lenora : 1261
Sam : 6971
Lenore : 1261
Rowan : 1297
Lukas : 2888
...
The actual search is being performed by the following segment:
.filter(e -> e.getValue().getOrDefault(0, 0) > 1000)
Here you can use an expression of arbitrary complexity to search for exactly what you need. In the following example, we search for key containing the string “mon” and total value more than 1000. The results are stored in another HashMap (for further processing).
Map<String,Map<Integer,Integer>> subset = namefreq
    .entrySet()
    .stream()
    .filter(e ->  e.getKey().contains("mon")&&e.getValue().getOrDefault(0, 0) > 1000)
    .collect(HashMap::new,
	     (m, e) -> m.put(e.getKey(), e.getValue()),
	     Map::putAll);
subset.forEach((k, v) -> System.out.println(k + " : " + v.get(0)));
// prints:
Simone : 3114
Desmond : 2498
Ramona : 8139
Raymond : 60506
...
6. Sort HashMap by Key
To sort a HashMap by key and print the mappings, we can do something like this.
namefreq
    .entrySet()
    .stream()
    .sorted((x, y) -> x.getKey().compareTo(y.getKey()))
    .forEach(e -> {
	    System.out.println(e.getKey() + " :");
	    e.getValue().forEach((kk, vv) -> {
		    System.out.println("  " + kk + " => " + vv);
		});
	});
// prints:
Lylia :
 0 => 6
 2009 => 6
Lyliana :
 0 => 15
 2007 => 5
 1998 => 5
 1999 => 5
...
To store the result (sorted map), we use a LinkedHashMap (which preserves the insertion order) as follows.
Map<String,Map<Integer,Integer>> subset = namefreq
    .entrySet()
    .stream()
    .sorted((x, y) -> x.getKey().compareTo(y.getKey()))
    .collect(LinkedHashMap::new,
	     (m, e) -> m.put(e.getKey(), e.getValue()),
	     Map::putAll);
subset.forEach((k, v) -> System.out.println(k + " : " + v.get(0)));
// prints:
Byanca : 90
Byanka : 79
Byran : 65
Byron : 7254
Cache : 10
Cadance : 30
Cade : 1874
...
7. Sort HashMap by Value
Sorting the HashMap by value is very similar to the above example. The following code sorts the name-count HashMap by total-count and prints the top 20 names.
namefreq
    .entrySet()
    .stream()
    .sorted((x, y) ->
	    y.getValue().get(0).compareTo(x.getValue().get(0)))
    .limit(20)
    .forEach(x -> System.out.println(x.getKey() + " => " +
				     x.getValue().get(0)));
// prints:
Michael => 422157
David => 364853
Robert => 347637
John => 310120
James => 274168
Daniel => 244229
Richard => 222633
Christopher => 215728
William => 209173
Anthony => 174064
...
Summary
Searching for a key in a HashMap involves applying a filtering pipeline to the entries. The same method is also applicable to search for the HashMap values. In fact arbitrarily complex expressions can be used with such a pipeline for search. We also learned how to sort the HashMap by keys or values and possibly store the results in a LinkedHashMap.
See Also
- Java Collections Introduction gives an overall picture of the most important classes and interfaces.
 - Java Collections – HashMap presents parsing a CSV to a HashMap as well as a multi-map.
 
	
What if i want to sort map on multiple value like
Name Dep_Id Salary Hours PerHourPay
xyz dev 40000 8.0 xxxx
dss del 30000 7.0 yyyy
now i want to sort data on basis of Salary Hours PerHourPay