I want to do a "group-by" on arrayList of HashMap Data structure. As my data is not fixed, so I don't have any fixed classes.
Data is shown as below.
[{"name":"laxman","state":"Karnataka","Mobile":9034782882},
{"name":"rahul","state":"Kerala","Mobile":9034782882},
{"name":"laxman","state":"karnataka","Mobile":9034782882},
{"name":"ram","state":"delhi","Mobile":9034782882}]
The above keys are not fixed, So, I can't have classes for it.
Data and formulas will be dynamical. But for now, I am taking this example to understand Stream.Collector on this data.
Now, I want to get the count on basis of name and state,
So basically I want to group-by on name and state and want to get count.
I tried to use Stream.Collector but am not able to achieve what I want.
You can accomplish this with Collectors.groupingBy, using a List as the key of the returned Map:
Map<List<String>, Long> result = yourListOfMaps.stream()
.collect(Collectors.groupingBy(
m -> Arrays.asList(String.valueOf(m.get("name")), String.valueOf(m.get("state"))),
Collectors.counting()));
This works well because all implementations of List in Java implement hashCode and equals consistently, which is a must for every class that is to be used as the key of any Map implementation.
You have to do groupingBy twice once on the key and once again on the value.
Map<String, Map<Object, Long>> map = listOfMap.stream().flatMap(a -> a.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry<String, String>::getKey,
Collectors.groupingBy(Map.Entry::getValue, Collectors.counting())));
Output
{mobile={9034782882=4}, name={rahul=1, laxman=2, ram=1}, state={Karnataka=2, delhi=1, Kerala=1}}
Related
I am doing a group by on a list of Objects as shown in the below code
Map<String, List<InventoryAdjustmentsModel>> buildDrawNumEquipmentMap = equipmentsAndCargoDetails.stream().
collect(Collectors.groupingBy(InventoryAdjustmentsModel :: getBuildDrawNum));
Now I know the values for all the keys would have only one element, so how can I reduce it to just
Map<String, InventoryAdjustmentsModel>
instead of having to iterate through or get the 0th element for all the keys.
You may use the toMap collector with a merge function like this.
Map<String, InventoryAdjustmentsModel> resultMap = equipmentsAndCargoDetails.stream().
collect(Collectors.toMap(InventoryAdjustmentsModel::getBuildDrawNum,
e -> e, (a, b) -> a));
Try it like this. By using toMap you can specify the key and the value. Since you said there were no duplicate keys this does not include the merge method. This means you will get an error if duplicate keys are discovered. Something I presumed you would want to know about.
Map<String, InventoryAdjustmentsModel> buildDrawNumEquipmentMap =
equipmentsAndCargoDetails.stream().
collect(Collectors.toMap(InventoryAdjustmentsModel::getBuildDrawNum,
model->model));
I created a Guava Multimap
ListMultimap<String,String> sampleMultimap = ArrayListMultimap.create();
And added some values which I take from a text file.
Now as an output I have
{Football=[10], Basketball=[1210, 1210, 1210, 120], Tennis=[1, 10, 100, 1000]}
I would like to sum each of the sports and find the highest sum. So expected result is
Basketball: 3750
Somehow I am stuck because I cant get the each one with samleMultimap.get(x) because key values are unknown and comes form text file.
Is there any way to get the expected result?
In the end you want Map<String, Integer> where values are sums of original multimap. You can use couple views:
Multimap#asMap() to have Map<K, Collection<V>> view of your multimap,
Maps#transformValues(Map, Function) - to create a view of a map where each value is transformed by a function.
Map<String, Integer> map = Maps.transformValues(multimap.asMap(), ints ->
ints.stream().mapToInt(Integer::intValue).sum());
Note that if you want to perform many operations on resulted map, read caveat in documentation and for example do ImmutableMap.copyOf(map):
The function is applied lazily, invoked when needed. This is necessary for the returned map to be a view, but it means that the function will be applied many times for bulk operations like Map.containsValue(java.lang.Object) and Map.toString(). For this to perform well, function should be fast. To avoid lazy evaluation when the returned map doesn't need to be a view, copy the returned map into a new map of your choosing.
With a ListMultimap you can call asMap() to get a view as a java.util.Map, then do normal map things.
If you change sampleMultimap to be an ArrayListMultimap instead of ListMultimap, then you can call keySet() directly (skip the asMap() call) and iterate over the resulting keys.
Here's an example showing how you could get each key from a ListMultimap (even if the underlying implementation is an instance of ArrayListMultimap), then get each associated value:
ListMultimap<String,String> sampleMultimap = ArrayListMultimap.create();
Map<String,String> mapView = sampleMultimap.asMap();
for (String key : mapView.keySet()) {
String value = mapView.get(key);
// do something with value
}
I have a HashMap which has keys as Date in Strings and value as an ArrayList of custom objects. I want to sort this hashmap on the basis of key. How can I do that?
HashMap<String,List<ClassName>> hashmap = new HashMap<String,List<ClassName>>();
When Hashmap is like this:
{"2015/07/15 : List("Object1","object2","object3")
"2015/07/14 :List("Object4" , "Object5")}
Please suggest.
You can use TreeMap instead of a HashMap . The TreeMap implements the Sorted Map interface.
As well as using a sorted map (as others have suggested) you can easily sort the keys when you use them rather than when you insert them.
For example, in Java 8:
treeMap.keySet().stream().sorted().forEach(System.out:println);
A nice thing about this is that it's easy to sort using different comparators without changing the collection.
For example, if you wanted to to sort by the number of items in the list value:
treeMap.keySet().stream().sorted(Comparator.comparingInt(k -> treeMap.get().size()))
This method is good for situations in which you insert and change values in the map often and then occasionally need the keys sorted for a particular operation. You get the performance of a HashMap but the flexibility to sort however you want on use.
You can use TreeMap, if you need the sorted map.
If you don't want to use TreeMap, then get the key and sort it as below.
HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
map.put("2015/07/15", list);
map.put("2015/07/17", list1);
map.put("2015/07/16", list1);
ArrayList<String> keyset = new ArrayList<String>(map.keySet());
Collections.sort(keyset);
First thing is you can use TreeMap when you need a sorted map. However you are storing date value as Strings. Then it become harder to compare each. So i recommend to use java.util.Date instead of String. You can use a date formatter when you adding to the map. Use following code.
TreeMap<Date, List> treeMap = new TreeMap<>();
You can specify the Comparator in the constructor of the TreeMap. So it's easy to sort up things according to your custom order.
I'm creating a HashMap using java8 stream API as follows:
Map<Integer, String> map = dao.findAll().stream()
.collect(Collectors.toMap(Entity::getType, Entity::getValue));
Now if an element is added to the collection where the key already exists, I just want to keep the existing element in the list and skip
the additional element. How can I achieve this? Probably I have to make use of BinaryOperation<U> of toMap(), but could anyone provide
an example of my specific case?
Yes, you need that BinaryOperation<U> and use it as a third argument for Collectors.toMap().
In case of a conflict (appearance of an already existing key) you get to choose between value oldValue (the existing one) and newValue. In the code example we always take value oldValue. But you are free to do anything else with these two values (take the larger one, merge the two etc.).
The following example shows one possible solution where the existing value always remains in the map:
Map<Integer, String> map = dao.findAll().stream()
.collect(Collectors.toMap(Entity::getType, Entity::getValue, (oldValue, newValue) -> oldValue));
See the documentation for another example.
ok,
here is my issue....I have a List<short>letterList which has for example: "1,2,3,4,5,6,7,8,9,10"
What Im doing is Im iterating over this list then passing the value into another method which returns a value:
so:
string value = null;
for(Short foo : letterList)
{
value = getSomeValue(foo) //returns a letter A or B or C
}
What Im trying to do is get a hashmap to look something like this:
key: a, value 1,5,7
key b, value: 2,3,4
key c, value: 6,8,9,10
not these values specifically, but you get my point
Im not sure how to do this I have tried creating a map with a <set<string>, List<short>
any suggestions would be appreciated
HashMap<Character, List<Short>> map
My understanding was you were looking for a simple way to store a list of values with a character? If so, use that above.
If you want to sort by letter (for easy printing out) use the following:
TreeMap<Character, List<Short>> map
You can get and of the values by using map.get('A') and using your standard methods to iterate through or get a certain value from the associated list.
Java has no built-in MultiMap, but you can either simulate a multimap (Map<String, List<Short>>) or try out Guava for example: https://code.google.com/p/guava-libraries/
Map<String, List<Short>>
The key (String) will be unique. The List<> will be able to hold a list of shorts.
If you want to make sure the numbers are unique as well as the keys, then use a Set instead of a list.
Remember to initialize the lists you put in the map (getting a key like "A" for the first time will return null, so check if it's null and if it is then create a List, put your value into it, and put the list into the map).
Not knowing your complete use case, I would suggest having a different look at your data structure organization. e.g.
Map<Integer, String> map = new HashMap<Integer, String>();
Where the keys are 1,2....10 as in your example and the values are
1 -> a
2 -> b
3 -> b
etc.
To get your original "list" you can use -
Set<Integer> numbers = map.keySet();