I have a multi-level map as follows:
Map<String, Map<String, Student> outerMap =
{"cls1" : {"xyz" : Student(rollNumber=1, name="test1")},
"cls2" : {"abc" : Student(rollNumber=2, name="test2")}}
Now I want to construct a list of string from the above map as follows:
["In class cls1 xyz with roll number 1",
"In class cls2 abc with roll number 2"]
I have written as follows, but this is not working, in this context I have gone through the post as well: Java 8 Streams - Nested Maps to List, but did not get much idea.
List<String> classes = outerMap.keySet();
List<String> studentList = classes.stream()
.map(cls ->
outerMap.get(cls).keySet().stream()
.map(student -> "In class "+ cls +
student + " with roll number " +
outerMap.get(cls).get(student).getRollNum() +"\n"
).collect(Collectors.toList());
You can simply use Map.forEach for this operation as:
List<String> messages = new ArrayList<>();
outerMap.forEach((cls, students) ->
students.forEach((name, student) ->
messages.add(convertToMessage(cls, name, student.getRollNumber()))));
where convertToMessage is a util as :
// this could be made cleaner using 'format'
String convertToMessage(String cls, String studentName, String rollNumber) {
return "In class" + cls + "--> " + studentName + " with roll number: " + rollNumber;
}
You may do it like so,
List<String> formattedOutput = outerMap
.entrySet().stream()
.flatMap(e -> e.getValue().entrySet().stream().map(se -> "In class " + e.getKey()
+ " " + se.getKey() + " with roll number " + se.getValue().getRollNumber()))
.collect(Collectors.toList());
You have to use the flatMap operator instead of map operator.
One method use Java 8 Stream and lambda function:
String format = "In class %s %s with roll number %d";
List<String> result = new ArrayList<>();
outerMap.entrySet().stream()
.forEach(v -> {
String className = v.getKey();
v.getValue().entrySet().stream()
.forEach(stringStudentEntry -> result.add(String.format(format,className,stringStudentEntry.getKey(),stringStudentEntry.getValue().getRollNumber())));
});
Related
I have a hashmap with 2 objects, Parcel and Deliverer. Both have a getName function. I want to loop the hashmap and print there names like (Parcel.getName(), Deliverer.getName()).
for (Map.Entry<Parcel, Deliverer> entry : deliveryList.entrySet()) {
for (Parcel key: entry) {
System.out.println("Package : " + key.getName());
for (Deliverer deliverer: entry) {
System.out.println("- Deliverer : " + deliverer.getName());
continue;
}
}
}
Another way can be using passing BiConsumer to forEach directly
deliveryList.forEach((key, value) -> System.out.println("Package: " + key.getName() + "- Deliver: " + value.getName()))
Not any different from #funkyjelly. An upvote :)
Same thing, just with Java8 collection foreach syntax.
deliveryList.entrySet().forEach( entry ->
System.out.println("Package : " + entry.getKey().getName());
System.out.println("Deliverer: " + entry.getValue().getName());
);
Once you have the map entries you'd only need to invoke getKey() to get Parcel and getValue() to get Deliverer for each entry.
Hence it should be like this :
for (Map.Entry<Parcel, Deliverer> entry : deliveryList.entrySet()) {
System.out.println("Package : " + entry.getKey().getName() +
"- Deliverer : " + entry.getValue().getName());
}
I have the below code to map each entry to a print statement, But it shows error.
Is something wrong in the way I understood Stream().map()?
How do I use System.out.println() within the streams API? how do I correct the following code?
public static void main(String[] args) {
Properties p = new Properties();
p.setProperty("name", "XYX");
p.setProperty("email", "xyx#mail.com");
p.setProperty("address", "addr-street-city");
p.entrySet().stream().map(e ->
System.out.println(" " + e.getKey().toString() + " " + e.getValue().toString() + ""));
}
If you want to use map:
p.entrySet().stream()
.map(e -> " "+e.getKey()+" "+e.getValue())
.forEach(System.out::println);
p.entrySet().forEach(e -> System.out.println(e.getKey() + " " + e.getValue()));
or
p.forEach((key, value) -> System.out.println(key + " " + value));
properties.entrySet().stream()
.map(entry -> String.format("%s : %s", entry.getKey(), entry.getValue()))
.forEach(System.out::println);
.map(...) - convert you key-value to a string format
.forEach(...) - prints your string
Your output should look like that :
address : addr-street-city
email : xyx#mail.com
name : XYX
p.entrySet().forEach(System.out::println)
map() should be used only if you want to alter/modify stream otherwise
for printing to the console forEach would do the work as it accepts BiConsumer to print key and value
Hi rectors all aver the world. I'm doing reactivi programming in Java. I'm a java/grails/react developer but first steps with reactive programming with Spring Boot, version 2 M7 in this case. In the next code:
#GetMapping(API_BASE_PATH + "/flux4")
public String flux4() {
StringBuilder sb = new StringBuilder();
Flux.just("alpha", "bravo", "charlie")
.map(String::toUpperCase)
.flatMap(s -> Flux.fromArray(s.split("")))
.groupBy(String::toString)
.sort(Comparator.comparing(GroupedFlux::key))
.map(group -> group.key() + " => " + group.count() + "; ")
.subscribe(sb::append);
return "flux 4: " + sb.toString();
}
I get the group.key() printed but how caon I get printed the group.count() ?
Any help is welcome
Cheers
Juan
I think I am reading the same book as you :)
Here is the solution using block().
Flux.just("alpha", "beta", "charlie")
.map(String::toUpperCase)
.flatMap(s -> Flux.fromArray(s.split("")))
.groupBy(String::toString)
.sort((o1,o2) -> o1.key().compareTo(o2.key()))
.flatMap(group -> Mono.just(Tuples.of(group.key(), group.count().block())))
.map(keyAndCount -> keyAndCount.getT1() + " => " + keyAndCount.getT2() + "; ")
I am wondering if there is an alternate way that doesn't call block()?. Now group.count() returns a Mono<Long>, and group.key() returns a String. It would be good if we could combine the two to form a Mono<Tuple2<String, Long>> without having to evaluate the result of the Mono. Seems like there should be a general method for doing that?
The book tried to use:
Mono.just(group.key()).and(group.count())
But that just listens for the completion events and returns a Mono<Void>, and therefore gives me compile errors...
Addendum: found it! Use the zip method:
Flux.just("alpha", "beta", "charlie")
.map(String::toUpperCase)
.flatMap(s -> Flux.fromArray(s.split("")))
.groupBy(String::toString)
.sort((o1,o2) -> o1.key().compareTo(o2.key()))
.flatMap(group -> Mono.zip(Mono.just(group.key()), group.count()))
.map(keyAndCount -> keyAndCount.getT1() + " => " + keyAndCount.getT2() + "; ")
I created a linkedlist object as follows
importBuffer = new BufferedReader(new FileReader(importcsvFile));
while ((line = importBuffer.readLine()) != null) {
// use comma as separator
String[] importedFile = line.split(cvsSplitBy); //cap,comune,provincia,stato
System.out.println("Codice Azienda " + importedFile[0] + " , Codice Cliente=" + importedFile[1] + " , Regione Sociale=" + importedFile[2] + " , Indrizzo=" + importedFile[3] + " , comune=" + importedFile[4] + " , provincia=" + importedFile[5] + " , stato=" + importedFile[6] +"]");
counter++;
PublicDefinition.importList.add(importBuffer.toString());
List customers = select.select(importedFile[0],importedFile[1], importedFile[3]);
if(!customers.isEmpty())
{
System.out.println("selected Customer : " + customers.size());
buffureList = customers;
Object a=List.class.cast(customers);
PublicDefinition.testingList.add(buffureList.toString());
System.out.println("selected Customer : " + PublicDefinition.importList.get(0));
System.out.println("selected Customer : " + PublicDefinition.testingList.getFirst());
updateCustomer = customers;
if(customers.get(0)==importedFile[0])
System.out.println("Matched Codice Azienda");
select.updateTable(importedFile[1], importedFile[3], "10.34", "11.40"); //String CodiceCliente, String indrizzo, String latitude, String longitute
}
}
when I try to access the elements for the linkedlist using
System.out.println("selected Customer : " + PublicDefinition.importList.get(0));
I got the output:
selected Customer : java.io.BufferedReader#420dc55b
I think this is the memory reference, but I want to retrieve the value of the linkedlist
my select function is:
public List<Customer> select(String codiceAzienda, String codiceCliente, String indrizzo) {
return jdbcTemplate.query(
"SELECT * FROM customers WHERE CodiceAzienda= ?",
new Object[] { codiceAzienda},
(rs, rowNum) -> new Customer(rs.getLong("id"),
rs.getString("CodiceAzienda"), rs.getString("Indrizzo"), rs.getString("codice_cliente"), rs.getString("Indrizzo")));
}
You added the toString() value of the importBuffer object, not the actual contents. The default toString() implementation (which every object inherits from... Object) returns ClassName#HashCode. So your output isn't wrong, but your input is.
See Object.toString() in the javadoc
Go ahead and perform:
PublicDefinition.importList.add(importBuffer.readLine());
Instead of :
PublicDefinition.importList.add(importBuffer.toString());
Since you are trying to output the contents of the buffered reader instead of the ClassName#Hashcode contents.
Replace
PublicDefinition.importList.add(importBuffer.toString());
with
PublicDefinition.importList.add(importedFile);
You are accidentally adding the string representation of BufferReader object, not the list of import files which sounds like your intention.
i need to trim all the String values
{
"startDate": "2015-06-29",
"endDate": "2015-07-04",
"category": "VIP ",
"name": " govind",
age: 10,
"place": " goa "
}
i am doing it by
JsonNode json = request().body().asJson();
CLassName cl = Json.fromJson(json , ClassName.class);
and trimming in setter of ClassName
suggest any other good approach because i know its not a good approach
If you can confirm that the JSON will not have quotes within values then for better performance I'd do the trimming on the raw text rather than the parsed version:
val text = request.body.asText
// RegEx explanation:
// space followed by asterisk means any number of spaces
// backward slash escapes the following character
val trimmed = text.map(_.replaceAll(" *\" *", "\""))
import play.api.libs.json.Json
val json = Json.parse(trimmed)
Java version:
import play.api.libs.json.*;
String text = request().body().asText();
String trimmed = text.replaceAll(" *\" *", "\"");
JsValue json = Json.parse(trimmed);
but changing the setter is not the right way to do it. As you would not be able to create the complete object again(even if it is required). Either you write a seperate Trimmer class which take this object and trim it. or some function in the same class. I would prefer a trimmer class
Try this:
public static void main(String[] args) {
String json =
"{"
+ " \"startDate\": \"2015-06-29\","
+ " \"endDate\": \"2015-07-04\","
+ " \"category\": \"VIP \","
+ " \"name\": \" govind\","
+ " age: 10,"
+ " \"place\": \" goa \""
+ "}";
Type stringStringMap = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> map = new Gson().fromJson(json, stringStringMap);
Map<String, String> trimed = map.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getKey().trim(), e.getValue().trim()))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
System.out.println(trimed);
// -> {endDate=2015-07-04, name=govind, place=goa, category=VIP, age=10, startDate=2015-06-29}
}