I have a map with Integer keys and values. I need to transform it into a String with this specific format: key1 - val1, key2 - val2, key3 - val3. Now, I'm using forEach to format each element, collect them into a List, and then do String.join();
List<String> ships = new ArrayList<>(4);
for (Map.Entry<Integer, Integer> entry : damagedMap.entrySet())
{
ships.add(entry.getKey() + " - " + entry.getValue());
}
result = String.join(",", ships);
Is there any shorter way to do it? And it would be good to do it with lambda, because I need some practice using lambdas.
I think you're looking for something like this:
import java.util.*;
import java.util.stream.*;
public class Test {
public static void main(String[] args) throws Exception {
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(2, "bar");
map.put(3, "baz");
String result = map.entrySet()
.stream()
.map(entry -> entry.getKey() + " - " + entry.getValue())
.collect(Collectors.joining(", "));
System.out.println(result);
}
}
To go through the bits in turn:
entrySet() gets an iterable sequence of entries
stream() creates a stream for that iterable
map() converts that stream of entries into a stream of strings of the form "key - value"
collect(Collectors.joining(", ")) joins all the entries in the stream into a single string, using ", " as the separator. Collectors.joining is a method which returns a Collector which can work on an input sequence of strings, giving a result of a single string.
Note that the order is not guaranteed here, because HashMap isn't ordered. You might want to use TreeMap to get the values in key order.
Related
So this problem has been taunting me for days. Any help is greatly appreciated!
I have made a LinkedHashMap which stores possible combinations for each part of a string and I'm trying to get all the permutations in an ArrayList of Strings, while maintaing the string order.
For example if the map is:
a=ab, b=c
The combinations would be:
ab
ac
abb
abc
I have tried simply looping each keys and values list, heap's algorithm which didn't work out for keeping the order of elements and also tried using recursion but i wasn't sure how. If anyone could point me in the right direction or hint me, that would be great. Thanks
Another map example of what im trying to do.
If the map is:
A=a, B=b
Output is:
AB (key1, key2)
Ab (key1, value2)
aB (value1, key2)
ab (value1, value2)
I basically want every combination of the whole map in order while alternating between keys and values of the map.
Try this.
static List<String> possiblePermutations(Map<String, String> map) {
int size = map.size();
List<Entry<String, String>> list = new ArrayList<>(map.entrySet());
List<String> result = new ArrayList<>();
new Object() {
void perm(int i, String s) {
if (i >= size) {
result.add(s);
return;
}
Entry<String, String> entry = list.get(i);
perm(i + 1, s + entry.getKey());
perm(i + 1, s + entry.getValue());
}
}.perm(0, "");
return result;
}
public static void main(String[] args) {
Map<String, String> map = new LinkedHashMap<>();
map.put("a", "ab");
map.put("b", "c");
map.put("x", "y");
List<String> result = possiblePermutations(map);
System.out.println(result);
}
output:
[abx, aby, acx, acy, abbx, abby, abcx, abcy]
It's very simple ...
Let's say the number of entries in your map is N
There is a 1-to-1 mapping between each possible permutation of such strings and an array boolean of length N. If the array has a true in position K, we pick the key from map entry K, otherwise we pick the value.
Therefore, to generate all possible permutations you need to generate all possible boolean arrays (same as binary numbers) of length N and then use each one to create a corresponding string.
So I saw some code online that I implemented into my program to sort a hashmap<String, int> based on the values of the integers, and it works successfully but only outputs the values, I need to store the values into a String list but don't understand the code well enough to do this and have been failing repeatedly, it is confusing me to have so many brackets.
If anyone could point me in the right direction that'd be helpful, I don't even know what to google to find out how to do this, thanks.
public List<String> getMaxList(int n, HashMap<String, Integer> itemCount){
List<Map.Entry<String, Integer>> maxList = new ArrayList<>();
Object[] a = itemCount.entrySet().toArray();
int n_iterator = n-1;
Arrays.sort(a, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Map.Entry<String, Integer>) o2).getValue()
.compareTo(((Map.Entry<String, Integer>) o1).getValue());
}
});
for (Object e : a) {
System.out.println(((Map.Entry<String, Integer>) e).getKey() + " : "
+ ((Map.Entry<String, Integer>) e).getValue());
if (n_iterator <= 0){
break;
} else {
n_iterator--;
}
}
return null;
}
}
How to refactor this Java code so it creates a String List of key:value pairs as opposed to printing them out?
Try it like this.
Create some data
Map<String, Integer> map =
Map.of("A", 10, "B", 3, "C", 8, "D", 2);
Now stream the map's entry set. Sort based on the value and convert the entry to a String:int string and put in a list.
List<String> list = map.entrySet().stream()
.sorted(Entry.comparingByValue()))
.map(e -> e.getKey() + ":" + e.getValue())
.collect(Collectors.toList());
System.out.println(list);
Prints
[D:2, B:3, C:8, A:10]
To sort in descending order, change the above sort method to
.sorted(Entry.<String,Integer>comparingByValue().reversed())
Note that the Entry comparator had to be witnessed with the types as the compiler could not discern them to properly apply the reversed() method. The above simply reverses the natural sorting order for Integers which is ascending.
Finally, not all objects provide methods that return comparators, so the following would also have worked.
.sorted(Comparator.comparing(Entry::getValue,
Comparator.reverseOrder()))
I'm having hash map with below values, in values I've date as string data type. I would like to compare all the dates which is available in map and extract only one key-value which has a very recent date.
I would like to compare with values not keys.
I've included the code below
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1999-01-01");
map.put("2", "2013-10-11");
map.put("3", "2011-02-20");
map.put("4", "2014-09-09");
map.forEach((k, v) -> System.out.println("Key : " + k + " Value : " + v));
}
}
The expected output for this one is:
Key 4 Value 2014-09-09
Use Collections.max with entrySet
Entry<String, String> max = Collections.max(map.entrySet(), Map.Entry.comparingByValue());
or
Entry<String, String> max = Collections.max(map.entrySet(),
new Comparator<Entry<String, String>>() {
#Override
public int compare(Entry<String, String> e1, Entry<String, String> e2) {
return LocalDate.parse(e1.getValue()).compareTo(LocalDate.parse(e2.getValue()));
}
});
This should work
Optional<Map.Entry<String, String>> result = map.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue));
System.out.println(result);
output is Optional[4=2014-09-09]
At the first glance, using String literals to represent Date is not a good approach and makes it more fragile and error prone. You would rather use LocalDate in the first place. However, with the assumption that you don't have any control over that data format (for instance, say, it is coming from another third party system), we can still devise an approach that solves the problem at hand. Here's how it looks.
Entry<String, String> maxEntry = map.entrySet().stream()
.max(Comparator.comparing(e -> LocalDate.parse(e.getValue())))
.orElseThrow(IllegalArgumentException::new);
The LocalDate.parse is used to convert the string representation of the date into a LocalDate which is a Comparable. That Comparable is then passed as a key to the Comparator construction method. And here's the output key-value pair upon the successful execution:
4=2014-09-09
If you can merely dispense with the String representation of date as suggested above, then you can make the above solution much more simpler and succinct.
Entry<String, LocalDate> maxEntry = map.entrySet().stream()
.max(Map.Entry.comparingByValue())
.orElseThrow(IllegalArgumentException::new);
This should provide the newest (aka largest) date as compared to the others.
String max = map.values().stream().reduce("0000-00-00",
(a, b) -> b.compareTo(a) >= 0 ? b
: a);
If you also want the key, then do this and return a Map.Entry. Requires Java 9+
Entry<String, String> ent =
map.entrySet().stream().reduce(Map.entry("0", "0000-00-00"),
(a, b) -> b.getValue().compareTo(a.getValue()) >= 0 ? b
: a);
System.out.println(ent.getKey() + " -> " ent.getValue());
This presumes your map is non-empty. if it is empty, then it returns a null. Works with Java 8+
Entry<String, String> ent = map.entrySet().stream().reduce(
(a, b) -> b.getValue().compareTo(a.getValue()) >= 0 ? b
: a).orElseGet(() -> null);
You can parse the string into LocalDate and sort it in reverse order
Entry<String, String> res = map.entrySet()
.stream()
.sorted(Comparator.comparing((Entry<String, String> entry)->LocalDate.parse(entry.getValue())).reversed())
.findFirst()
.orElse(null); // if not present return null or empty Entry
You can do either :
import java.util.Map.Entry;
Entry<String, String> maxEntry = map.entrySet()
.stream()
.max(Entry.comparingByValue());
.orElseThrow(NoSuchElementException::new);
or :
Entry<String, String> max = Collections.max(map.entrySet(), Entry.comparingByValue());
Both will produce the same result.
In java 8 I know that they added the parallel stream which takes advantage of multicore processors, and I know that you can use it with something like this:
List<String> list = new ArrayList<String>();
list.parallelStream().forEach(str -> System.out.println(str));
But how would I achieve something like this with a HashMap?
Map<String, Integer> map = new HashMap<String, Integer>();
// won't work, because the Map class doesn't have the .parallelStream()
map.parallelStream().forEach((str, num) -> System.out.println(str + ":" + num));
Does anyone know how to do something like this? Thanks
You can't stream a Map directly, but you can stream its entry set, given with the entrySet() method. Extract the key and value from the entry object.
map.entrySet()
.parallelStream()
.forEach(entry -> System.out.println(entry.getKey() + ":" + entry.getValue()));
You can get the 'entry set' from the hash map by calling map.entrySet(), you can call parallelStream() on the returned entry set.
Please note that the returned object is a set of Map.Entry. You can get the key and value from an entry set item by calling getKey() and getValue() on it respectively. As follows:
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.entrySet().parallelStream().forEach((e) -> System.out.println(e.getKey() + ":" + e.getValue()));
First time here so I hope this makes sense!
I have a Map which contains a String as it's Key, and a List of Strings as it's Value. I need to iterate over all vlaues contained within each List within the Map.
So, first I want to get the Keys, which works:
Set<String> keys = theMap.keySet();
This returns me a Set containing all my Keys. Great :)
This is where I've got stuck - most of the info on the web seems to assume that the values I'd want returned from the Key would be a simple String or Integer, not another Set, or in this case a List. I tried theMap.values() but that didn't work, and I tried a forloop / for:eachloop, and neither of those did the trick.
Thanks y'all!
for(List<String> valueList : map.values()) {
for(String value : valueList) {
...
}
}
That's really the "normal" way to do it. Or, if you need the key as well...
for(Map.Entry<String, List<String>> entry : map.entrySet()) {
String key = entry.getKey();
for (String value : entry.getValue()) {
...
}
}
That said, if you have the option, you might be interested in Guava's ListMultimap, which is a lot like a Map<K, List<V>>, but has a lot more features -- including a Collection<V> values() that acts exactly like what you're asking for, "flattening" all the values in the multimap into one collection. (Disclosure: I contribute to Guava.)
I recommend iterating over Map.entrySet() as it is faster (you have both, the key and the value, found in one step).
Map<String, List<String>> m = Collections.singletonMap(
"list1", Arrays.asList("s1", "s2", "s3"));
for (Map.Entry<String, List<String>> me : m.entrySet()) {
String key = me.getKey();
List<String> valueList = me.getValue();
System.out.println("Key: " + key);
System.out.print("Values: ");
for (String s : valueList) {
System.out.print(s + " ");
}
}
Or the same using the Java 8 API (Lambda functions):
m.entrySet().forEach(me -> {
System.out.println("Key: " + me.getKey());
System.out.print("Values: ");
me.getValue().forEach(s -> System.out.print(s + " "));
});
Or with a little bit of Java Stream API mapping hardcore and method reference :-)
m.entrySet().stream().map(me -> {
return "Key: " + me.getKey() + "\n"
+ "Values: " + me.getValue().stream()
.collect(Collectors.joining(" "));
})
.forEach(System.out::print);
And the output is, as expected:
Key: list1
Values: s1 s2 s3
You need a Map<String, List<String>>
The left hand side String is the key, the right hand side List<String> is the value, which in this case is a List of Strings
Another example with the Java 8 API (lambda function).
When you want to iterate over:
Map<String, List<String>> theMap = new HashMap<>();
theMap.forEach((key, value) -> {
System.out.println("KEY: " + key);
System.out.print("VALUES: ");
value.forEach(System.out::println);
});