Java how to use TreeMap - java

I have an TreeMap with for key an Integer and for value Coords (int x, int y).
I would like to get all the values (my coords) associated with an specific key.
For exemple :
key = 1, coords = [0, 0]
key = 1, coords = [0, 1]
key = 2, coords = [1, 0]
key = 3, coords = [1, 1]
foreach myMap.getKeys() as key
do
myMap.getValuesFrom(key)
store it in a new list
end do
I don't really know how to use Map, your helps is welcome.

First point - Map cannot have two different values associated with the same key. If you really need to do this, you can create a map of lists, like this:
Map<Integer, List<Integer>> map = new TreeMap<Integer, List<Integer>>();
The following code traverses the keys of the map and puts related values to the list:
Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
List<Integer> list = new ArrayList<Integer>();
for (Integer key : map.keySet()) {
list.add(map.get(key));
}
More correct way to do the same thing:
Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
List<Integer> list = new ArrayList<Integer>(map.values());
If you really need several values mapped to the same key, try this:
Map<Integer, List<Integer>> map = new TreeMap<Integer, List<Integer>>();
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
System.out.println("Map values for key \"" + entry.getKey() + "\":");
for (Integer value : entry.getValue() == null ? new ArrayList<Integer>() : entry.getValue()) {
System.out.print(value + " ");
}
System.out.println();
}
This code simply writes all map keys and its values into System.out.
For further information, try to read Map Javadoc and List Javadoc.

Related

What is the best practices to merge two maps

How can I add a new map to existing map. The maps have the same type Map<String, Integer>. If the key from new map exists in the old map the values should be added.
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
//Data added
//Now what is the best way to iterate these maps to add the values from both?
By add, I assume you want to add the integer values, not create a Map<String, List<Integer>>.
Before java 7, you'll have to iterate as #laune showed (+1 to him). Otherwise with java 8, there is a merge method on Map. So you could do it like this:
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
oldMap.put("1", 10);
oldMap.put("2", 5);
newMap.put("1", 7);
oldMap.forEach((k, v) -> newMap.merge(k, v, (a, b) -> a + b));
System.out.println(newMap); //{1=17, 2=5}
What it does is that for each key-value pair, it merges the key (if it's not yet in newMap, it simply creates a new key-value pair, otherwise it updates the previous value hold by the existing key by adding the two Integers)
Also maybe you should consider using a Map<String, Long> to avoid overflow when adding two integers.
for( Map.Entry<String,Integer> entry: newMap.entrySet() ) {
// get key and value from newMap and insert/add to oldMap
Integer oldVal = oldMap.get( entry.getKey() );
if( oldVal == null ){
oldVal = entry.getValue();
} else {
oldVal += entry.getValue();
}
newMap.put( entry.getKey(), oldVal );
}
Hope that this is what you meant

How to get values of some specific range of keys in HashMap in Java?

How to get values of some specific range of keys in HashMap in Java?
Suppose I have a HashMap having keys and values as follows:
Map <Integer , String> map = hnew HashMap <Integer , String>();
map.put(1 , "A");
map.put(3 , "C");
map.put(2 , "B");
map.put(4 , "D");
map.put(5 , "E");
map.put(6 , "F");
Now how should I iterate to get values for keys 2 to 5 (that is 2, 4, and 5 but not 3)?
Either:
Loop through the list of keys you want and query the HashMap for the value corresponding to that key (be aware some may be null).
Loop through the entrySet of the HashMap looking to see if the key is one that you want.
Use a map that keeps order (LinkedHashMap added in correct order) and iterate through, extracting the required block of entries.
While Java's Map interface does not define a special order on its elements, a map implementation may very well define one. The sub-interface SortedMap defines that all keys must be naturally ordered and adds new methods like subMap to access value ranges. The sub-sub-interface NavigableMap adds even more.
The most prominent implementation in Java's standard library of SortedMap is TreeMap:
SortedMap<Integer, String> map = new TreeMap<>();
map.put(1 , "A");
map.put(3 , "C");
map.put(2 , "B");
map.put(4 , "D");
map.put(5 , "E");
map.put(6 , "F");
System.out.println(map.subMap(2, 6).values()); // [B, C, D, E]
A Map has no order on the keys. It does not matter if you put the key 3 and then the key 2. This "order" is not preserved.
I don't see anything special about the keys 2, 4, and 5. So you could do this:
for (int key : new int[] {2, 4, 5}) {
String value = map.get(key);
}
If you want maintain the order of the insertion for map then use LinkedHashMap. Then you can iterate the map through the specific value .
Declare an array of Integer for which you would like the value.
int a[] = {2,4,5};
for(int i : a) {
String str = map.get(i);
doSomething(str); //method to operate on that string.
}
If you want to have a predictable order in the keys of a Map, you need to use subclass LinkedHashMap.
Here's an example of code that does what you want:
public class Snippet {
public static void main(String[] args) {
LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();
map.put(1, "A");
map.put(3, "C");
map.put(2, "B");
map.put(4, "D");
map.put(5, "E");
map.put(6, "F");
System.out.println(valuesBetween(2, 5, map));
}
public static List<String> valuesBetween(int from, int to, LinkedHashMap<Integer, String> map) {
List<String> result = new ArrayList<>();
boolean inRange = false;
for (Map.Entry<Integer, String> entry : map.entrySet()) {
if (entry.getKey() == from)
inRange = true;
if (inRange)
result.add(entry.getValue());
if (entry.getKey() == to)
break;
}
return result;
}
}
This will print:
[B, D, E]
if you want get int key values from HashMap
you should create new Set Array and put values to it.
**Set has specificity for sort it's keys**.
Map<Integer,String> students = new HashMap<>();
students.put(1, "Rashid");
students.put(3, "Cosqun");
students.put(2, "Ulvi");
Set<Integer> keys = students.keySet();
for (int key : keys) {
System.out.println(key+" "+students.get(key));
}
Dog, this is all you need:
SortedMap<Integer, String> map = new TreeMap<Integer, String>();
map.subMap(2, 6);

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());
}

iterating two maps into a third map on key from both maps

I have two maps with key as an integer and value as a double.
I want to create a third map sorted on key and value would be a list of doubles from both the maps.
map1:
1, 90.00
5, 75.45
8, 76.50
map2:
4, 12.00
5, 322.09
8, 11.09
9, 21.00
final map:
1, (90.00,0.00)
5, (75.45,322.09)
8, (76.50,11.09)
9, (0.00, 21.00)
As clear from above, if a key in one of the map is missing in the other map, the value in the final map for the other map should be defaulted to 0.00
Map firstMap = new HashMap<Integer, Double>();
Map secondMap = new HashMap<Integer, Double>();
Map finalMap = new HashMap<Integer, List<Double>>();
firstMap.put(1, 90.00);
firstMap.put(5, 75.45);
firstMap.put(8, 76.50);
secondMap.put(4, 12.00);
secondMap.put(5, 322.09);
secondMap.put(8, 11.09);
secondMap.put(9, 21.00);
I can use putAll method to put all keys into the third map. But how to put the values as I want ?
Thanks for reading!
Simply do
// Create a sorted map
Map<Integer, List<Double>> finalMap = new TreeMap<Integer, List<Double>>();
Set<Integer> keys = new HashSet<Integer>();
keys.addAll(firstMap.keySet());
keys.addAll(secondMap.keySet());
for (Integer key : keys) {
double first = firstMap.containsKey(key) ? firstMap.get(key) : 0.0;
double second = secondMap.containsKey(key) ? secondMap.get(key) : 0.0;
finalMap.put(key, Arrays.asList(first, second));
}
Using Guava it's as simple as
Multimap<Integer, Double> finalMultiMap = ArrayListMultimap.create();
finalMultiMap.putAll(Multimaps.forMap(firstMap));
finalMultiMap.putAll(Multimaps.forMap(secondMap));
Map<Integer, Collection<Double>> finalMap = finalMultiMap.asMap();
The following code would perform the requested operation
List<Map<Integer, Double>> originals = getOriginalLists();
Map<Integer, List<Double>> result = new HashMap<Integer, List<Double>>();
for (Map<Integer, Double> original : originals) {
for (Map.Entry<Integer, Double> entry : original.entrySet()) {
if (!result.containsKey(entry.getKey())) {
result.put(entry.getKey(), new ArrayList<Double>());
}
result.get(entry.getKey()).add(entry.getValue());
}
}
It works one a list of maps, so the solutions is not restricted to two maps.

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