I have a HashMap<String, LinkedList<Integer>> and I want to create a hashMapInverted<LinkedList<Integer>, Set<String>> which contains in keys the lists, values of first map, and the values the set of strings which have the same list in first map.
How can I do this?
You can do:
Map<LinkedList<Integer>, Set<String>> mapInverted = new HashMap<>(myMap.size());
for(Entry<<String, LinkedList<Integer>> entry : myMap.entrySet()) {
String key = entry.getKey();
LinkedList<Integer> list = entry.getValue();
Set<String> strings = mapInverted.get(list);
if(strings == null) { // the list has not already been put in the map
strings = new HashSet<String>(); // create a new set
mapInverted.put(list, strings); // put the list and the new set
}
strings.add(key);
}
You can try -
Map<String, LinkedList<Integer>> map =new HashMap<String, LinkedList<Integer>>();
Map<LinkedList<Integer>, Set<String>> invertMap = new HashMap<LinkedList<Integer>, Set<String>>();
for (Entry<String, LinkedList<Integer>> entry : map.entrySet()) {
if(invertMap.containsKey(entry.getValue())){
invertMap.get(entry.getValue()).add(entry.getKey());
}else{
Set<String> set = new HashSet<String>();
set.add(entry.getKey());
invertMap.put(entry.getValue(), set);
}
}
Related
This is my list.
list = Stream.of(
"06|20|1",
"11|20|2",
"11|20|2",
"07|207|6",
"11|207|2",
"07|207|6",
).collect(Collectors.toList());
I have a hashmap such as:
HashMap<String, HashMap<String, String>> hashMap = new HashMap<>();
HashMap<String, String> newHash = new HashMap<>();
And my code is
for (String line : list) {
String key, value, priority;
key = line.split("\\|", -1)[1];
value = line.split("\\|", -1)[0];
priority = line.split("\\|", -1)[2];
if (hashMap.containsKey(key)) {
HashMap<String, String> getPriority = hashMap.get(key);
Map.Entry<String, String> entry = getPriority.entrySet().iterator().next();
String oldKey = entry.getKey();
String previousPrior = getPriority.get(oldKey);
if (Integer.parseInt(priority) > Integer.parseInt(previousPrior)) {
getPriority.remove(oldKey);
getPriority.put(value,priority);
hashMap.put(key, getPriority);
}
} else {
newHash.put(value, priority);
System.out.println(newhas);
hashMap.put(key, newhas);
}
}
I want to have the have the key with highest priority only such as:
{20={11=2},207={07=6}}
as 11 and 7 has the highest valaues in 20 and 207.
But i am getting all values in the inner hashmap.
How about using streams instead?
Map<String, Map<String, String>> map = list.stream()
.map(line -> line.split("\\|"))
.sorted(Comparator.comparingInt(line -> Integer.parseInt(line[2])))
.collect(Collectors.toMap(
line -> line[1],
line -> Map.of(line[0], line[2]),
(low, high) -> high));
Ideone Demo
For each new key that you insert in your Map variable in the else condition of your code you need to create new HashMap to insert it along with the new key.
What you are doing is using the same newhas variable for all the keys in your Map variable.
So change this
else {
newhas.put(value, priority);
System.out.println(newhas);
Map.put(key, newhas);
}
to
else {
newHas = new HashMap<>();
newhas.put(value, priority);
System.out.println(newhas);
Map.put(key, newhas);
}
Ideone Demo
I have a data structure as follows:
Map<String,ArrayList<String>> graph = new HashMap<String,ArrayList<String>>();
This is essentially a hash map which puts string values as keys and stores array list of strings in the value for the keys.
Now I am trying to reverse the key value pattern to make value the key and key the value. The way I am doing it is as follows:
private Map<String,ArrayList<String>> reverseAdjList(Map<String,ArrayList<String>> adjList){
Map<String,ArrayList<String>> tGraph = new HashMap<String,ArrayList<String>>();
for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
ArrayList<String> values = new ArrayList<>();
values.add(key);
ArrayList<String> value = entry.getValue();
for(String v:value){
if(tGraph.containsKey(v)){
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
return tGraph;
}
So this works for me in reversing the hash map keys values pattern for small data set however when I try it on a larger dataset I run into
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.addAll(ArrayList.java:579)
at GraphProcessor.reverseAdjList(GraphProcessor.java:67)
at GraphProcessor.SCC(GraphProcessor.java:135)
at GraphProcessor.<init>(GraphProcessor.java:50)
at GraphProcessor.main(GraphProcessor.java:250)
I know this is a very naïve and wrong approach to do it, what is a better and correct way to do it?
There's a bug in your code:
for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
ArrayList<String> values = new ArrayList<>(); // Wrong place for this variable.
values.add(key);
ArrayList<String> value = entry.getValue();
for(String v:value){
if(tGraph.containsKey(v)){
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
The local variable values should be in the nested for loop, otherwise values are accumulated for all later new key v and will cost a lot of memory if your dataset is large, it should be:
private Map<String, ArrayList<String>> reverseAdjList(Map<String, List<String>> adjList) {
Map<String, ArrayList<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
for (String v : value) {
ArrayList<String> values = new ArrayList<>();
values.add(key);
if (tGraph.containsKey(v)) {
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
return tGraph;
}
But actually you don't need to create a new List instance for each inner for step, try the following code with JDK 1.8:
private Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
Map<String, List<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
for (String value : entry.getValue()) {
tGraph.computeIfAbsent(value, v -> new ArrayList<>()).add(entry.getKey()); // Updated according comment from #shmosel
}
}
return tGraph;
}
If you're using older version of jdk, you can try:
private Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
Map<String, List<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
for (String value : entry.getValue()) {
List<String> newValues = tGraph.get(value);
if (newValues == null) {
newValues = new ArrayList<>();
tGraph.put(value, newValues);
}
newValues.add(entry.getKey());
}
}
return tGraph;
}
Hope this could be helpful :-)
For instance if I have a map with integer and strings:
Map<Integer, String> myMap = new HashMap<Integer, String>();
This map would contain key values of Integers and values of names.
What I am trying to do is make a new map, that copies all the values (names) from theMap and makes them the keys for the new map. Now the tricky part I can't get, is that I want the values of the new map to be the numbers, but if there are multiple numbers that correspond to the same name I want them to be held in an Set.
Example of new map:
Map<String, Set<Integer>> returnMap = new TreeMap<String, Set<Integer>>();
So if "John" corresponds to 1,2,3,4. I would like the new map to contain a key of "John" with a Set containing 1,2,3,4
Google's Guava library has a nice Multimap class which maps keys to multiple values. If you use it, you can take advantage of a host of helper methods:
SetMultimap<String, Integer> returnMap =
Multimaps.invertFrom(Multimaps.forMap(myMap), TreeMultimap.create());
It's not that tricky :)
Map<Integer, String> map = ... //Your map
Map<String, Set<Integer>> reverseMap = new TreeMap<String, Set<Integer>>();
for(Map.Entry<Integer, String> entry : map.entrySet()) {
Integer key = entry.getKey();
String value = entry.getValue();
Set<Integer> set;
if(reverseMap.containsKey(value)) {
set = reverseMap.get(value);
set.add(key);
} else {
set = new HashSet<Integer>();
set.add(key);
reverseMap.put(value, set);
}
}
for second entry of idAndTags the inner-map is shuffled but not for the first
FIRST APPROACH!
for (Map.Entry<String, Map<String, String>> entryOne : idAndTags.entrySet()) {
List keys = new ArrayList(entryOne.getValue().keySet());
System.out.println(keys);
Collections.shuffle(keys);
System.out.println(keys);
}
SECOND APPROACH!
for (Map.Entry<String, Map<String, String>> entryOne : idAndTags.entrySet()) {
shufTags = new HashMap<String, String>();
Map<String, String> tags = entryOne.getValue();
System.out.println(tags);
final List<String> vs = new ArrayList<String>(tags.values());
Collections.shuffle(vs);
final Iterator<String> vIter = vs.iterator();
for (String k : tags.keySet())
shufTags.put(k, vIter.next());
System.out.println(shufTags);
}
Map#.keySet() returns a view of the key set, which doesn't support ordering. Shuffling it has no effect on the map.
You can not change the order of iteration of a HashMap, but a LinkedHashMap iterates itself in the order of insertion, so you can replace the inner maps with a LinkedHashMap and use a shuffled key set to drive the insertion.
didn't have a choice, solved it like this... seems to work for me!
Map<String, Map<String, String>> _idAndTagsShuffled = new HashMap<String, Map<String, String>>();
for (Map.Entry<String, Map<String, String>> entryOne : _idAndTags.entrySet()) {
ArrayList<String> keys = new ArrayList(entryOne.getValue().keySet());
shuffledMap = new HashMap<String, String>();
do {
shuffled = new ArrayList<String>();
Collections.shuffle(keys);
for (String key : keys) {
shuffled.add(key);
}
int count = 0;
isShuffled = false;
for (String tag : entryOne.getValue().keySet()) {
if (!tag.equals(shuffled.get(count))) {
isShuffled = true;
}
count++;
}
} while (!isShuffled);
_idAndTagsShuffled.put(entryOne.getKey(), shuffledMap);
}
java code
Hashtable<String, Integer> gettingStatus = searchActiveAssetStatus();
ArrayList<String> statusValue = new ArrayList<String>();
ArrayList<String> statusCount = new ArrayList<String>();
Set<String> keys = gettingStatus.keySet();
for (String key : keys) {
if (key.contains("Active")) {
statusValue.add(key);
}
if (key.contains("Abandoned")) {
statusValue.add(key);
}
if (key.contains("Deleted")) {
statusValue.add(key);
}
}
for the above i have stored Key in an separate array list (available), at the same time if that key exist in hashtable i want to store the value for that corresponding key in another array list (statusCount) how?
You may use the entrySet() method instead of the keySet() method:
Set<Entry<String, Integer>> entries = gettingStatus.entrySet();
for (Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
if (key.contains("Active")) {
statusValue.add(key);
// Store value
}
if (key.contains("Abandoned")) {
statusValue.add(key);
// Store value
}
if (key.contains("Deleted")) {
statusValue.add(key);
// Store value
}
}
If I got your question right you just have to ask for the value of the corresponding key and put it in the list:
Hashtable<String, Integer> gettingStatus = searchActiveAssetStatus();
ArrayList<String> statusValue = new ArrayList<String>();
ArrayList<String> statusCount = new ArrayList<String>();
Set<String> keys = gettingStatus.keySet();
for (String key : keys) {
if (key.contains("Active") || key.contains("Abandoned") || key.contains("Deleted")) {
statusValue.add(key);
statusCount.add(gettingStatus.get(key).toString());
}
}
Or as Benjamin said just take entrySet() which makes it even easier.