I want to connect a HashMap's key and value to a string with ':', and transform them to a list.
Example:
Map<String,String> tags = new HashMap<>();
tags.put("k1","v1");
tags.put("k2","v2");
then I want to get the string
k1:v1,k2:v2
my code is:
private String transe(Map<String, String> tags) {
if (tags == null || tags.isEmpty()) {
return DEFAULT_STATUS_GROUP;
}
List<String> tagKVList = new ArrayList<>();
tags.forEach((key, value) -> tagKVList.add(String.join(":", key, value)));
tagKVList.sort((tag1, tag2) -> tag1.compareTo(tag2));
return tagKVList.stream().collect(Collectors.joining(","));
}
How can I remove the local variable tagKVList and make the code clearer?
You don't need the intermediate List. You can Stream the entrySet, map each entry to a String and collect to a single String as you already do :
return tags.entrySet().stream()
.map(e-> String.join(":", e.getKey(), e.getValue()))
.sorted()
.collect(Collectors.joining(","));
Related
public List<ErrorMessage> getErrorMessageDetails(ValidationResult validationResult, String severity) {
Map<List<String>, List<String>> errorObjectsMap = new HashMap<>();
//errorCode= some values in List of strings
//errorMessage= some values in List of strings
errorObjectsMap.put(errorCode, errorMessage);
List<ErrorMessage> errorMessageList = new ArrayList<>();
for (Map.Entry<List<String>, List<String>> pair : errorObjectsMap.entrySet()) {
List<String> errorCodeMsg = pair.getKey() == null ? new ArrayList<>() : pair.getKey();
List<String> errorMsg = pair.getValue() == null ? new ArrayList<>() : pair.getValue();
errorMessageList.add(new ErrorMessage(errorCodeMsg.get(0), errorMsg.get(0)));
// So in above line of code i want to iterate both list k,v and use its keys and values to create list of List<ErrorMessage> errorMessageList dynamically without using index of lists
}
return errorMessageList;
}
Please refer above java method to suggestions.
Could someone please help to write logic to iterate dynamically in most concise way in java?
Thank you in advance :)
The presented method does not use any of the input arguments validationResult and severity and it shows that the map contains only one entry.
However, to simply build a list of error messages, Stream API could be used to convert the stream of map entries into the list of ErrorMessage where the lists in map entries are iterated by indexes provided by IntStream and flatMap is applied to join the error messages from all entries:
public List<ErrorMessage> getErrorMessageDetails(ValidationResult validationResult, String severity) {
Map<List<String>, List<String>> errorObjectsMap = new HashMap<>();
//errorCode= some values in List of strings
//errorMessage= some values in List of strings
errorObjectsMap.put(errorCode, errorMessage);
// assuming there are more entries
return errorObjectsMap.entrySet()
.stream() // Stream<Map.Entry<List<String>, List<String>>>
.filter(e -> e.getKey() != null && e.getValue() != null
&& !e.getKey().isEmpty() && !e.getValue().isEmpty()
)
.flatMap(e -> IntStream.range(0, Math.min(e.getKey().size(), e.getValue().size()))
.mapToObj(i -> new ErrorMessage(
e.getKey().get(i), e.getValue().get(i)
)) // Stream<ErrorMessage>
)
.collect(Collectors.toList());
}
I have the following query header method:
public Map<String, List<String>> query(Predicate<String> valuePredicate)
Before this, I implementated another method with a specific column (label). It was:
public Map<String, List<String>> query(String keySelector,Predicate<String> valuePredicate) {
try {
final List<String> row = frameInfo.get(keySelector);
List<Integer> indices = IntStream.range(0, row.size()).filter(columnIndex -> valuePredicate.test(row.get(columnIndex))).boxed().collect(Collectors.toList());
Map<String, List<String>> auxMap = new HashMap<>();
for (Map.Entry<String, List<String>> entry : frameInfo.entrySet()) {
for (int columnIndex : indices) {
auxMap.putIfAbsent(entry.getKey(), new ArrayList<>());
auxMap.get(entry.getKey()).add(entry.getValue().get(columnIndex));
}
}
return auxMap;
}catch (Exception e){
return null;
}
How could I implementate the new method with just 1 argument (valuePredicate)?
It seems to me that you could do it like so. Since the predicate tests a string from a list which can be streamed, I don't see why you need to iterate the indices.
Stream the entrySet from frameInfo
then flatmap e.getValue() (a list) and apply the predicate
preserve the key and filtered value in a String array
then group based on the key
public Map<String, List<String>> queryAll(Predicate<String> valuePredicate) {
return frameInfo.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.filter(valuePredicate)
.map(s -> new String[] { e.getKey(), s }))
.collect(Collectors.groupingBy(arr -> arr[0],
Collectors.mapping(arr -> arr[1],
Collectors.toList())));
}
I'm tossing this one in as well, it's a rewrite of your existing method.
it simply streams the list for the supplied key, applies the filter and populates the map. Since there is only one key, you could just return a list.
public Map<String, List<String>> query(String keySelector,
Predicate<String> valuePredicate) {
return frameInfo.get(keySelector).stream()
.filter(valuePredicate)
.collect(Collectors.groupingBy(a -> keySelector));
}
If I misunderstood something, let me know and I will try to correct it.
I'm having trouble to find an element inside my String array contained inside my HashMap. I have a String that is indeed inside this String[] but doing the following does not work.
if (groupOuMap.containsValue("someString")) {
groupOu = "someString";
}
My goal is to find the corresponding key of my HashMap where the value is found.
Exemple with a sample of my map :
nedcard.nl -> ["Wijchen account"]
mic.ad -> ["Ayutthaya4", "Brazil", "Changi", "Dresden", "Guangzhou"]
If I search for the String Brazil, I'd like to have a new Array of String which would be :
String[] groupOu = {"mic.ad", "Brazil"};
I have tried to used groupOuMap.values().contains() as well with no success.
Am I doing this wrong? Thank you!
In Java the easiest way to do this is probably just to iterate through each key-value pair in the map, and search for the first occurrence of the search term in the array that is the value. When found, return both the key and the value. If not found, return null.
public static String[] keyContainingValue(HashMap<String, String[]> map, String searchFor) {
for (String key : map.keySet()) {
String[] values = map.get(key);
// construct for replicating List.contains() on a primitive array
if (Arrays.stream(values).anyMatch(i -> i.equals(searchFor))) {
return {key, searchFor};
}
}
return null;
}
You can filter over the entrySet via Streams.
public static String[] search(Map<String, String[]> map, String value){
return map.entrySet().stream()
.filter(e -> Arrays.stream(e.getValue()).anyMatch(value::equals))
.findAny().map(e -> new String[]{e.getKey(), value}).orElse(null);
}
//...
Map<String, String[]> map = Map.of("mic.ad", new String[]{"Ayutthaya4", "Brazil", "Changi", "Dresden", "Guangzhou"}, "nedcard.nl", new String[]{"Wijchen account"});
System.out.println(Arrays.toString(search(map, "Brazil"))); // [mic.ad, Brazil]
Demo
Using Map of key to iterate and based on condition returning HashMap,need to collect return map below code.
trying to convert below java code in java 8
for (String key : sectionsJson.keySet()) {
Map<String, Object> section = (Map<String, Object>) sectionsJson.get(key);
if (index == (Integer) section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, key);
return section;
}
}
any suggestion.
It looks like you want to produce a Map having at most a single entry.
Map<String,Object> map =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(e -> new SimpleEntry<> (SECTION_FIELD_KEY_SECTION_KEY, e.getKey ()))
.limit(1)
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
It looks like your original code is simpler.
Perhaps you can simply search for the desired key:
String value =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
since you are producing a Map having (at most) a single value and a constant key, so the value is the only data the Stream pipeline should be searching for.
As per your existing code. You are returning the map as soon as it finds any match. Same thing you can do using java 8 as well.
Optional<Integer> findAny = sectionsJson.keySet().stream().filter(key -> {
Map<String, Object> section = (Map<String, Object>)sectionsJson.get(key);
if (index == (Integer)section.get("SECTION_FIELD_KEY_INDEX")) {
section.put("SECTION_FIELD_KEY_SECTION_KEY", key);
return true;
}
return false;
}).findFirst();
if (findAny.isPresent()) {
System.out.println(sectionsJson.get(findAny.get()));
}
Depending on what you want to achieve following might be also possible solutions:
simplifying the loop
for (Map.Entry<String, Map<String, Object>> entry : sectionsJson.entrySet()) {
Map<String, Object> section = entry.getValue();
if (index == section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, entry.getKey());
return section;
}
}
// add the code for the case when no section was found
separate stream processing and mutating the element
// find the section
Optional<Map.Entry<String, Map<String, Object>>> first = sectionsJson.entrySet().stream()
.filter(e -> (Integer) e.getValue().get(SECTION_FIELD_KEY_INDEX) == index)
.findFirst();
// mutate the section
if (first.isPresent()) {
Map.Entry<String, Map<String, Object>> sectionJson = first.get();
sectionJson.getValue().put(SECTION_FIELD_KEY_SECTION_KEY, sectionJson.getKey());
return sectionJson.getValue();
}
// add the code for the case when no section was found
I want to convert a javax.persistence.Tuple into a HashMap, but like this, it inserts the last element of the tuple and takes also the alias and data type. How can I improve this method so it takes values of the tuple?
public Map<String, Object> tuplesToMap(List<Tuple> data){
Map<String, Object> values = new HashMap<>();
data.forEach(tuple -> {
tuple.getElements().forEach(
element -> {
values.put(element.getAlias(), tuple.get(element));
}
);
});
return values;
}
with java 8 is simply :
return data.stream()
.collect(Collectors.toMap(
t -> t.get(0, String.class),
t -> t.get(1, Object.class)));
Seems to be working :
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data
){
return data.stream()
.map(tuple -> { // per each tuple of the input List
// creating a new HashMap
Map<String, Object> resultItem = new HashMap<>();
// filling the created HashMap with values of
tuple.getElements().forEach( // each column of the tuple
col -> { resultItem.put(col.getAlias(), tuple.get(col)); }
);
// returning the created HashMap instead of the current Tuple
return resultItem;
})
// collecting & returning all the created HashMap-s as a List
.collect(Collectors.toList());
}
But usualy both single & list conversions are required, so let's combine them :
public static Map<String/*UPPERCASE*/, Object> jpaTupleToMap(
javax.persistence.Tuple data /*CASE INSENSITIVE*/
){
Map<String, Object> result =
new HashMap<>(); // exactly HashMap since it can handle NULL keys & values
data.getElements().forEach(
col -> { result.put(col.getAlias(), data.get(col)); }
);
return result;
}
//-------------------------
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data /*CASE INSENSITIVE*/
){
return data.stream() // List<Tuple> -> Tuple1,..TupleN
.map(tuple -> jpaTupleToMap(tuple)) // Tuple1 -> HashMap1,..TupleN -> HashMapN
.collect(Collectors.toList()); // HashMap1,..HashMapN -> List
}
The element.getAlias() you're using as the key for the hashmap is probably same for some of the elements.
Map keys are unique, meaning, if you insert entries (1, "one") and then (1, "two"), the first value will be overridden by the latter. If you want to have multiple values mapped to one key, use Map<String, Collection<Object>>, or a Multimap from Guava, which is exactly the same thing.
You can insert into multimap with this function - if the key is not in the map, create a new ArrayList and add it to the map, otherwise return the existing one. Then, insert the value to the list:
values
.computeIfAbsent(element.getAlias, k -> new ArrayList<>())
.add(tuple.get(element));