How to convert List to Map - Key of Map should be a combination of multiple keys
#AllArgsConstructor
#NoArgsConstructor
#Data
#Builder
public class Student {
private long id;
private String firstName;
private String lastName;
private String street;
private String city;
public static void main(String[] args) {
List<Student> students = Arrays.asList(
Student.builder().id(1).firstName("John").lastName("Doe").build(),
Student.builder().id(1).firstName("Jane").lastName("Doe").build(),
Student.builder().id(1).firstName("Mike").lastName("Doe").build(),
Student.builder().id(1).firstName("Jack").lastName("Doe").build()
);
LinkedHashMap<Long, String> collect = students.stream()
.collect(Collectors.toMap(
Student::getId, Student::getFirstName, (x, y) -> x + ", " + y, LinkedHashMap::new));
System.out.println(collect);
// Answer I am expecting is Ex: {1johnDoe=[id=1,firstName=John, lastName=Doe]}
}
}
Using Java 17
I have implemented the below code using some of the latest java features apart from Java 8.
Records in java 14 : As of JDK 14, we can replace our data classes with records. Records are immutable classes that require only the type and name of fields. We do not need to create constructor, getters, setters, override toString() methods, override hashcode and equals methods.
List.of() in java 9: It is a static method that returns the immutable list of elements passed as arguments. Here in the below scenario, we will get the list of four student objects.
public class Test {
public static void main(String[] args) {
record Student(long id, String firstName, String lastName,String street, String city){}
Student s1 = new Student(1,"F1","L1","S1","C1");
Student s2 = new Student(2,"F2","L2","S2","C2");
Student s3 = new Student(3,"F3","L3","S3","C3");
Student s4 = new Student(4,"F4","L4","S4","C4");
Map<String,Student> output =
List.of(s1,s2,s3,s4).stream().collect(Collectors.toMap(x -> x.id() + x.firstName(),
Function.identity(), (k, v) -> k, LinkedHashMap::new));
System.out.println(output);
}
}
Output:
{1F1=Student[id=1, firstName=F1, lastName=L1, street=S1, city=C1], 2F2=Student[id=2, firstName=F2, lastName=L2, street=S2, city=C2], 3F3=Student[id=3, firstName=F3, lastName=L3, street=S3, city=C3], 4F4=Student[id=4, firstName=F4, lastName=L4, street=S4, city=C4]}
You can do as follows
LinkedHashMap<String, Student> collect = students.stream()
.collect(
Collectors.toMap(
student->(String.join("", Long.toString(student.getId()),student.getFirstName(),student.getLastName())),
student->student,
(v1,v2)->v1,
LinkedHashMap::new));
collect.forEach((k,v)->System.out.println(k+"="+v));
I think, you want key as String and value as Student into map
I am trying to sort a list by lastName and age descending using Java 8 - I can get to the point of sorting both firstName and age - but not by firstName and age descending. Please help.
#Getter
#Setter
#AllArgsConstructor
#ToString
class ABCE {
private String firstName;
private String lastName;
private int age;
}
// Sort by firstName and then by age descending
list = list.stream().sorted(Comparator.comparing(ABCE::getFirstName).thenComparing(ABCE::getAge))
.collect(Collectors.toList());
list.stream().forEach(System.out::println);
Did you want both name and age descending? Your reversed() reverses all the comparisons prior. If you just want to reverse based on ages, do it as follows. I simplified it somewhat by using a record with just a first name.
record ABCE(String getFirstName, int getAge) {
}
public static void main(String[] args) {
List<ABCE> list = List.of(new ABCE("A", 10),
new ABCE("B", 10), new ABCE("B", 12),
new ABCE("C", 10), new ABCE("C", 10));
// Sort by firstName ascending and then by age descending
list = list.stream()
.sorted(Comparator.comparing(ABCE::getFirstName)
.thenComparing(ABCE::getAge,
Comparator.reverseOrder()))
.collect(Collectors.toList());
list.stream().forEach(System.out::println);
}
Prints
ABCE[getFirstName=A, getAge=10]
ABCE[getFirstName=B, getAge=12]
ABCE[getFirstName=B, getAge=10]
ABCE[getFirstName=C, getAge=10]
ABCE[getFirstName=C, getAge=10]
I have an enum looks like:
public enum Movies {
SCIFI_MOVIE("SCIFI_MOVIE", 1, "Scifi movie type"),
COMEDY_MOVIE("COMEDY_MOVIE", 2, "Comedy movie type");
private String type;
private int id;
private String name;
Movies(String type, int id, String name) {
this.type = type;
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
}
I know that I can use stream to create a Set of Movies enum with:
Set<Movie> Movie_SET = Arrays.stream(Movie.values()).collect(Collectors.toSet());
What if I want to create a Set of enum Movies id. Is there a way to do that with stream?
Yes, assuming you have a getter for your id, your Movies enum might look like this:
public enum Movies {
SCIFI_MOVIE("SCIFI_MOVIE", 1, "Scifi movie type"),
COMEDY_MOVIE("COMEDY_MOVIE", 2, "Comedy movie type");
private String type;
private int id;
private String name;
Movies(String type, int id, String name) {
this.type = type;
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
}
Then, you can get the set of ids by using Stream.map():
Set<Integer> movieIds = Arrays.stream(Movies.values()).map(Movies::getId)
.collect(Collectors.toSet());
BTW, an alternative way to create the set of all movies is to use EnumSet.allOf():
Set<Integer> movieIds = EnumSet.allOf(Movies.class).stream().map(Movies::getId)
.collect(Collectors.toSet());
You can use EnumSet implementation for this purpose e.g.
For obtaining the Set of Movies:
Set<Movies> movies = EnumSet.allOf(Movies.class);
For obtaining only movies ids:
Set<Integer> moviesIds = movies.stream().map(Movies::getId).collect(Collectors.toSet());
If you are able to get stream of Enum values then rest could easily be achieved.
You could use custom Collector impl (My favorite of all time), see example below of a custom collector:-
Set<Integer> movieIds = Arrays
.stream(Movies.values())
.collect(
HashSet::new,
(set, e) -> set.add(e.getId()),
HashSet::addAll
);
Or you could use map to fetch ids only and the collect to collect these ids to a Set as usual.
Set<Integer> movieIds = Arrays
.stream(Movies.values())
.map(Movies::getId)
.collect(Collectors.toSet());
I need to create a pivot project considering a list of three levels:
public class Value
{
private DateTime DayMonth;
private float value;
private float variation;
[...]
}
public class Element
{
private String description;
private List<Value> values;
private List<Element> elements;
[...]
}
public class User
{
private String name;
private List<Element> elements;
[...]
}
What I need is to make pivot pages for each of the diferent Value.DayMonth of each element. So, when I visualize the data, I can see the value e variation of each element, and if I want to see these indicators for another day of the month I just go to the next page.
I'm having syntax troubles.
public class Student
{
int StudentId;
string Name;
}
public class Course
{
int CourseId;
List<Student> Students;
}
int[] studentIds = { 5, 7, 12 };
List<Course> allCourses = myDataContext.Courses.ToList();
Using Lambda expressions or query expressions, how do I get a filtered list of all the Courses containing any of the Students in the array studentIds?
var result = from course in allCourses
where course.Students.Any(x => studentIds.Contains(x.StudentId))
select course;