Printing a Map with a nested Map - java

I have a Map of the following kind:
HashMap<String, Map<String, Integer>> resultMap = new HashMap<>();
Where String(Key) = Website address;
Map<String,Integer> = String(key) -search word, Integer(value) - counter for found words.
How to print the Map correctly so that it looks like this:
webSite1 - randomWord = 30, randomWord2 = 15, randomWord3 = 0
webSite2 - randomWord = 9, randomWord2 = 8, randomWord3 = 1
Thanks in advance for any ideas!

Map has simple iterator forEach((key, value) -> your_consumer), and the entries in the nested map may be converted into strings joined using Collectors.joining, so printing may be done as follows:
resultMap.forEach((k, v) ->
System.out.println(k + " - " +
v.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining(", "))
);

If I've correctly understood you:
In the outer loop, you should iterate the nested maps (as values),
and in the internal loop(s) you can finally iterate keys and values of the nested map.
HashMap<String, Map<String, Integer>> map = new HashMap<>();
for (Map<String, Integer> nestedMap : map.values())
{
for (String key : nestedMap.keySet()) {
// some actions here
}
for (Integer value : nestedMap.values()) {
// some actions here
}
}

Related

Sorting a entrySet<String, String> by keys

In my entrySet I have the next values:
name -> "someName"
nameSpace -> "someNameSpace"
version -> "someVersion"
I'm iterating over this entrySet and adding its values to a final object, my problem is that I need to add the values in the order:
nameSpace -> "someNameSpace"
name -> "someName"
version -> "someVersion"
With nameSpace first. Not pretty sure if it's possible to achieve that using a stream or something more sophisticated. I'm doing the process manually.
public static void main(String [] args){
SortedMap<String, String> coordinates = new TreeMap<>();
coordinates.put("name", "nameValue");
coordinates.put("nameSpace", "nameSpaceValue");
coordinates.put("version", "versionValue");
String name = coordinates.get("name");
String nameSpace = coordinates.get("nameSpace");
String version = coordinates.get("version");
/*Object.add("name", name);
Object.add("nameSpace", nameSpace);
Object.add("version", version);*/
}
Thanks!
It seems natural sorting is not applicable to the keys in this specific order: nameSpace, name, version, therefore SortedMap / TreeMap would require some very custom/hardcoded comparator:
SortedMap<String, String> coordinates = new TreeMap<>(
(a, b) -> b.startsWith(a) && !a.startsWith(b) ? 1 : a.compareTo(b)
);
coordinates.put("version", "versionValue");
coordinates.put("nameSpace", "nameSpaceValue");
coordinates.put("name", "nameValue");
// iterating the map
// coordinates.forEach((k, v) -> Object.add(k, v));
coordinates.forEach((k, v) -> System.out.println(k + " -> " + v));
Output:
nameSpace -> nameSpaceValue
name -> nameValue
version -> versionValue
Another approach would be to use LinkedHashMap capable of maintaining the insertion order and fix this order as necessary:
Map<String, String> coordinates = new LinkedHashMap<>();
// add entries in expected order
coordinates.put("nameSpace", "nameSpaceValue");
coordinates.put("name", "nameValue");
coordinates.put("version", "versionValue");
Similar approach would be to use an unsorted map and a list of keys in the desired order.
Map<String, String> coordinates = new HashMap<>();
coordinates.put("name", "nameValue");
coordinates.put("nameSpace", "nameSpaceValue");
coordinates.put("version", "versionValue");
List<String> keyOrder = Arrays.asList("nameSpace", "name", "version");
keyOrder.forEach(k -> System.out.println(k + " -> " + coordinates.get(k)));
However, it seems that method add of the custom object requires both key and value anyway, so the order of populating the fields should not be relevant.

Counting same Strings from Array in Java

How can I count the same Strings from an array and write them out in the console?
The order of the items should correspond to the order of the first appearance of the item. If there are are two or more items of a kind, add an "s" to the item name.
String[] array = {"Apple","Banana","Apple","Peanut","Banana","Orange","Apple","Peanut"};
Output:
3 Apples
2 Bananas
2 Peanuts
1 Orange
I tried this:
String[] input = new String[1000];
Scanner sIn = new Scanner(System.in);
int counter =0;
String inputString = "start";
while(inputString.equals("stop")==false){
inputString = sIn.nextLine();
input[counter]=inputString;
counter++;
}
List<String> asList = Arrays.asList(input);
Map<String, Integer> map = new HashMap<String, Integer>();
for (String s : input) {
map.put(s, Collections.frequency(asList, s));
}
System.out.println(map);
But I don't know how to get the elements out of the Map and sort them like I would like.
You can use a Map to put your result, here is a simple example:
public static void main(String args[]){
String[] array = {"Apple","Banana","Apple","Peanut","Banana","Orange","Apple","Peanut"};
Map<String, Integer> result = new HashMap<>();
for(String s : array){
if(result.containsKey(s)){
//if the map contain this key then just increment your count
result.put(s, result.get(s)+1);
}else{
//else just create a new node with 1
result.put(s, 1);
}
}
System.out.println(result);
}
Use Java streams groupingBy and collect the results into a Map<String, Long> as shown below:
String[] array = {"Apple","Banana","Apple","Peanut","Banana","Orange","Apple", "Peanut"};
Map<String, Long> map = Stream.of(array).collect(Collectors.
groupingBy(Function.identity(), //use groupingBy array element
Collectors.counting())); //count number of occurances
System.out.println(map);//output the results of the Map
Java 8 would allow a pretty elegant way of doing this with groupingBy and counting. Using a LinkedHashMap instead of the default map should handle the ordering:
Arrays.stream(array)
.collect(Collectors.groupingBy(Function.identity(),
LinkedHashMap::new,
Collectors.counting()))
.entrySet()
.forEach(e -> System.out.println(e.getValue() +
"\t" +
e.getKey() +
(e.getValue() > 1 ? "s" : "")));
use java 8
Map<String, Long> myMap = Stream.of(array).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Grouping similar items using hashmap

I have a input like this
0 [0.327097, 0.326998, 0.0]
0 [1.056364, 0.601873, 0.0]
0 [1.273154, 1.656441, 0.0]
1 [1.48469, 0.095074, 0.0]
1 [1.061504, -0.768175, 1.0]
i need to sort them as
0 : [ [0.327097, 0.326998, 0.0] ,[1.056364, 0.601873, 0.0], [1.273154, 1.656441, 0.0]]
1 : [ [1.48469, 0.095074, 0.0], [1.061504, -0.768175, 1.0]]
I did like this ..
but i am not getting the same output.my output is getting repeated.
Can u pls help me out...
Map<String, Collection<String>> groupMap = new HashMap<String, Collection<String>>();
String[] subparts = finalline.split("\\[");
String groupKey;
String value;
if (subparts.length == 1) {
groupKey = null;
value = subparts[0];
}
else if (subparts.length == 2) {
groupKey = subparts[0];
value = subparts[1];
}
else {
throw new IllegalArgumentException("Can not parse string");
}
Collection<String> groupContents = groupMap.get(groupKey);
if (groupContents == null) {
groupMap.put(groupKey, groupContents = new ArrayList<String>());
}
groupContents.add(value);
}
The value of the groupMap map is another collection, so you can iterate through that collection within the outer loop as given below
Map<String, Collection<String>> groupMap = new HashMap<String, Collection<String>>();
for(String key : groupMap.keySet()){
System.out.println("Key: " + key);
Collection<String> values = groupMap.get(key);
for(String value : values){
System.out.println("value: " + value);
}
}
Map<String, Collection<String>> groupMap = new HashMap<String, Collection<String>>();
for (String s : groupMap.keySet()) {
for (String s1 : groupMap.get(s)) {
System.out.println(s1);
}
}
A collection within a collection just means nested loops--just like with a 2D array.
I'd suggest using a HashMultimap from "Guava" instead.
It helps make it easy to handle a mapping from keys to multiple values and is a general way to associate keys with arbitrarily many values.
Here's an example.
Multimap<String, String> map = HashMultimap.create();
map.put("1", "a");
map.put("1", "b");
map.put("2", "c");
map.put("2", "d");
And now you can use the "values()" view to iterate over the values in the map.
for(String value : map.values()) {
System.out.println(value);
}
This will give you
a
b
c
d
Or if you want the key along with the value, then you can use the "entries()" view.
for(Map.Entry<String, String> entry : map.entries()) {
System.out.println("Key: " + entry.getKey() + " Value : " + entry.getValue());
}
This will give you
Key: 1 Value : a
Key: 1 Value : b
Key: 2 Value : c
Key: 2 Value : d
And if you're looking for a plain old java simple solution
Map<String, List<String>> map = new HashMap<String, List<String>>();
// ... Some code to put values in the map
for(String key : map.keySet()){
System.out.println("\nKey: " + key);
List<String> values = map.get(key);
for(String value : values) {
System.out.println("Value: " + value);
}
}
The best and most efficient way to iterate over a map's entries is:
Map<String, Collection<String>> map;
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
System.out.print(entry.getKey()+":");
for (String str : entry.getValue())
System.out.println(str);
}
This code will produce the output you requested.
Note that at no point are the keys looked up. When you iterate over the entry set, you have direct access to both the (typed) key and (typed) value.
The most efficient way to loop over the entries in your Map is as follows:
Map<String, Collection<String>> groupMap = new HashMap<String, Collection<String>>();
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
System.out.println("Key: "+entry.getKey());
for (String val : values) {
System.out.printlnln("Value: "+entry.getValue());
}
}

Java: How to get set of keys having same value in hashmap

I have a hashmap as below:
1->x
2->y
3->x
4->z
Now i want to know all keys whose value is x (ans: [1,3] ). what is best way to do?
Brute force way is to just iterate over map and store all keys in array whose value is x.
Is there any efficient way for this.
Thanks
A hashmap is a structure that is optimized for associative access of the values using the keys, but is in no way better in doing the reverse then an array for instance. I don't think you can do any better then just iterate. Only way to improve efficiency is if you have a reverse hash map as well(i.e. hash map where you hold an array of keys pointing to a given value for all values).
You can use a MultiMap to easily get all those duplicate values.
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "x");
map.put(2, "y");
map.put(2, "z");
map.put(3, "x");
map.put(4, "y");
map.put(5, "z");
map.put(6, "x");
map.put(7, "y");
System.out.println("Original map: " + map);
Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
multiMap.put(entry.getValue(), entry.getKey());
}
System.out.println();
for (Entry<String, Collection<Integer>> entry : multiMap.asMap().entrySet()) {
System.out.println("Original value: " + entry.getKey() + " was mapped to keys: "
+ entry.getValue());
}
Prints out:
Original map: {1=x, 2=z, 3=x, 4=y, 5=z, 6=x, 7=y}
Original value: z was mapped to keys: [2, 5]
Original value: y was mapped to keys: [4, 7]
Original value: x was mapped to keys: [1, 3, 6]
Per #noahz's suggestion, forMap and invertFrom takes fewer lines, but is arguably more complex to read:
HashMultimap<String, Integer> multiMap =
Multimaps.invertFrom(Multimaps.forMap(map),
HashMultimap.<String, Integer> create());
in place of:
Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
multiMap.put(entry.getValue(), entry.getKey());
}
If Java 8 is an option, you could try a streaming approach:
Map<Integer, String> map = new HashMap<>();
map.put(1, "x");
map.put(2, "y");
map.put(3, "x");
map.put(4, "z");
Map<String, ArrayList<Integer>> reverseMap = new HashMap<>(
map.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getValue)).values().stream()
.collect(Collectors.toMap(
item -> item.get(0).getValue(),
item -> new ArrayList<>(
item.stream()
.map(Map.Entry::getKey)
.collect(Collectors.toList())
))
));
System.out.println(reverseMap);
Which results in:
{x=[1, 3], y=[2], z=[4]}
If Java 7 is preferred:
Map<String, ArrayList<Integer>> reverseMap = new HashMap<>();
for (Map.Entry<Integer,String> entry : map.entrySet()) {
if (!reverseMap.containsKey(entry.getValue())) {
reverseMap.put(entry.getValue(), new ArrayList<>());
}
ArrayList<Integer> keys = reverseMap.get(entry.getValue());
keys.add(entry.getKey());
reverseMap.put(entry.getValue(), keys);
}
As an interesting aside, I experimented with the time required for each algorithm when executing large maps of (index,random('a'-'z') pairs.
10,000,000 20,000,000
Java 7: 615 ms 11624 ms
Java 8: 1579 ms 2176 ms
If you are open to using a library, use Google Guava's Multimaps utilities, specifically forMap() combined with invertFrom()
Yup, just brute force. You can make it fast by also storing a Multimap from Value -> Collection of Key, at the expense of memory and runtime cost for updates.
HashMap computes the hashcode() of the key, not of the values. Unless you store some kind of additional information, or consider using a different data structure, I think the only way you can get this is brute force.
If you need to perform efficient operation on the values, you should think whether you're using the appropriate data structure.
If you are using a hashmap there is no efficient way doing it but iterating the values
If you already have a map, you should consider using Google's Guava library to filter the entries you're interested in. You can do something along the lines of:
final Map<Integer, Character> filtered = Maps.filterValues(unfiltered, new Predicate<Character>() {
#Override
public boolean apply(Character ch) {
return ch == 'x';
}
});
I agree with George Campbell but for java 8 I would do it a bit easier:
Map<String, List<Integer>> reverseMap = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(
Map.Entry::getKey,
Collectors.toList())));
Try This.....
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("cust_tenure", "3_sigma");
hashMap.put("cust_age", "3_sigma");
hashMap.put("cust_amb_6m_sav", "3_sigma");
hashMap.put("cust_amb_6m_chq", "3_sigma");
hashMap.put("cust_total_prod_6m", "3_sigma");
HashMap<String, ArrayList<String>> result = new LinkedHashMap<String, ArrayList<String>>();
for (String key : hashMap.keySet()) {
ArrayList<String> colName = null;
if (!result.containsKey(hashMap.get(key))) {
colName = new ArrayList<String>();
colName.add(key);
result.put(hashMap.get(key), colName);
} else {
colName = result.get(hashMap.get(key));
colName.add(key);
result.put(hashMap.get(key), colName);
}
System.out.println(key + "\t" + hashMap.get(key));
}
for (String key : result.keySet()) {
System.out.println(key + "\t" + result.get(key));
}
System.out.println(hashMap.size());
}

Recursively or iteratively retrieve key-value combinations from a HashMap

I want to retrieve k,v-pairs from a HashMap.
The entrys are like this:
a = 3,4
b = 5,6
and so on. I need combinations of these values.
a=3, b=5
a=3, b=6
a=4, b=5
a=4, b=6
I don't know how many keys and how many entrys the values have. With entrySet I can get the values but not combinations. It looks like recursion but how?
Here's my code:
HashMap<String, String[]> map = new HashMap<String, String[]>();
BufferedReader file = new BufferedReader(new FileReader("test.txt"));
String str;
while ((str = file.readLine()) != null) {
// ... logic
map.put(key, value);
}
System.out.println("number of keys: " + map.size());
for (Map.Entry<String, String[]> entry : map.entrySet()) {
for (String value : entry.getValue()) {
System.out.println(entry.getKey() + ": " + value);
}
}
file.close();
You can try the following code:
public void mapPermute(Map<String, String[]> map, String currentPermutation) {
String key = map.keySet().iterator().next(); // get the topmost key
// base case
if (map.size() == 1) {
for (String value : map.get(key)) {
System.out.println(currentPermutation + key + "=" + value);
}
} else {
// recursive case
Map<String, String[]> subMap = new HashMap<String, String[]>(map);
for (String value : subMap.remove(key)) {
mapPermute(subMap, currentPermutation + key + "=" + value + ", ");
}
}
}
No guarantees on memory efficiency or speed. If you want to preserve the order of the keys in the map, you will have to pass in a TreeMap and change the code to use a TreeMap under the recursive case.
As the base case suggests, I'm assuming you have at least one entry in your map.
You can obtain a Cartesian product of map key-value combinations using a map and reduce approach.
Try it online!
Map<String, String[]> map = Map.of(
"a", new String[]{"3", "4"},
"b", new String[]{"5", "6"});
List<Map<String, String>> comb = map.entrySet().stream()
// Stream<List<Map<String,String>>>
.map(e -> Arrays.stream(e.getValue())
.map(v -> Map.of(e.getKey(), v))
.collect(Collectors.toList()))
// summation of pairs of list into a single list
.reduce((list1, list2) -> list1.stream()
// combinations of inner maps
.flatMap(map1 -> list2.stream()
// concatenate into a single map
.map(map2 -> {
Map<String, String> m = new HashMap<>();
m.putAll(map1);
m.putAll(map2);
return m;
}))
// list of combinations
.collect(Collectors.toList()))
// otherwise, an empty list
.orElse(Collections.emptyList());
// output, order may vary
comb.forEach(System.out::println);
Output, order may vary:
{a=3, b=5}
{a=3, b=6}
{a=4, b=5}
{a=4, b=6}
See also: Cartesian product of map values
It looks to me like you really want a MultiMap. In particular, ArrayListMultimap allows duplicate entries:
ArrayListMultimap<String, String> map = ArrayListMultimap.create();
for each line in file:
parse key k
for each value in line:
parse value v
map.put(k, v);
for (Map.Entry<String, String> entry : map.entries()) {
String key = entry.getKey();
String value = entry.getValue();
}
If you want a cartesian product of maps, you could compute that directly using recursion, or you could iterate over the maps: create a list of iterators and iterate odometer-style; when iterator N reaches its end, advance iterator N+1 and reset iterators 1..N.
Just poked around and found this SO question.
So I'd recommend you use guava's Sets.cartesianProduct for the cartesian product. Here's my poking around code, which you could adapt to your input logic:
String key1 = "a";
Set<Integer> values1 = Sets.newLinkedHashSet(Arrays.asList(1, 2, 3, 4));
String key2 = "b";
Set<Integer> values2 = Sets.newLinkedHashSet(Arrays.asList(5, 6, 7));
String key3 = "c";
Set<Integer> values3 = Sets.newLinkedHashSet(Arrays.asList(8, 9));
List<String> keys = Arrays.asList(key1, key2, key3);
Set<List<Integer>> product = Sets.cartesianProduct(values1, values2, values3);
for (List<Integer> values : product) {
for (int i = 0; i < keys.size(); ++i) {
String key = keys.get(i);
int value = values.get(i);
System.out.print(key + "=" + value + "; ");
}
System.out.println();
}

Categories