I am having 2 Employee List. One List contains the name and employeeId and the second List contains employeeId and mobile number. employee id is the primary key.
The requirement is to get the List which contains the id, Name, and mobile no using streaming.
public class MainApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
Employee emp1 = new Employee(101, "Shiv1");
Employee emp2 = new Employee(102, "Shiv2");
Employee emp3 = new Employee(103, "Shiv3");
Employee emp4 = new Employee(104, "Shiv4");
Employee emp5 = new Employee(101, 00001);
Employee emp6 = new Employee(101, 00002);
Employee emp7 = new Employee(101, 00003);
Employee emp8 = new Employee(101, 00004);
List<Employee> employeeNameList = new ArrayList<Employee>();
employeeNameList.add(emp1);
employeeNameList.add(emp2);
employeeNameList.add(emp3);
employeeNameList.add(emp4);
List<Employee> employeeMobileList = new ArrayList<Employee>();
employeeMobileList.add(emp5);
employeeMobileList.add(emp6);
employeeMobileList.add(emp7);
employeeMobileList.add(emp8);
employeeNameList.stream()
.filter(item -> item.getId() == 3)
.map(i -> i.setMobileNo(9089));
}
}
You can create a mapping of the empId to their name using the first list.
Map<Integer, String> empIdToName = employeeNameList.stream()
.collect(Collectors.toMap(Employee::getId, Employee::getName, (a, b) -> a));
Use such a mapping to create the objects further while iterating through the second and looking up this map, such as:
List<Employee> employees = employeeMobileList.stream()
.filter(item -> empIdToName.containsKey(item.getId()))
.map(i -> new Employee(i.getId(), empIdToName.get(i.getId()), i.getMobileNo()))
.collect(Collectors.toList());
Related
lets say I have:
bob:V
bob:A
bob:B
bob:C
bob:C
sally:B
sally:C
sally:A
steve:A
steve:B
steve:C
how do I store:
the values as:
bob={V,A,B,C,C}, sally={B,C,A}, steve={A,B,C}
and for any guy who has a sequence A,B,C repeated how do I get that person name?
I am fairly new to Java and Im trying to implement this scenario, as I dont see anything like this in this communtiy.
here is my final answer: first stored the list into a map and then used collectors to loop through and map it to their respective attributes.
public class Solution{
static List<String> doWork(List<LogItem> eventsInput) {
Map<String, String> personMap = eventsInput.stream()
.collect(Collectors.toMap(LogItem::getUserId, p -> Character.toString(p.getEventChar()), String::concat));
System.out.println("person map is \n" + personMap);
BiPredicate<Entry<String, List<String>>, String> contains =
(entry, attr) -> entry.getValue().stream()
.collect(Collectors.joining()).contains(attr);
String attributes = "ABC";
List<String> results = personMap.entrySet().stream()
.filter(e -> e.getValue().contains(attributes))
.map(Entry::getKey).collect(Collectors.toList());
return results;
}
public static void main(String[] args){
List<LogItem> exampleInputItems = new ArrayList<>();
exampleInputItems.add(new LogItem("bob", 'V'));
exampleInputItems.add(new LogItem("bob", 'A'));
exampleInputItems.add(new LogItem("steve", 'A'));
exampleInputItems.add(new LogItem("bob", 'B'));
exampleInputItems.add(new LogItem("bob", 'C'));
exampleInputItems.add(new LogItem("bob", 'C'));
exampleInputItems.add(new LogItem("steve", 'B'));
exampleInputItems.add(new LogItem("sally", 'B'));
exampleInputItems.add(new LogItem("steve", 'C'));
exampleInputItems.add(new LogItem("sally", 'C'));
exampleInputItems.add(new LogItem("sally", 'A'));
List<String> returnedNames = doWork(exampleInputItems);
if (returnedNames.size() != 2) {
throw new RuntimeException("Wrong number of names found. Found: " + returnedNames);
}
if (!returnedNames.contains("bob")) {
throw new RuntimeException("Did not find \"bob\" in the returnedNames: " + returnedNames);
}
if (!returnedNames.contains("steve")) {
throw new RuntimeException("Did not find \"steve\" in the returnedNames: " + returnedNames);
}
System.out.println("The example passed.");
}
static class LogItem {
public String userId;
public char eventChar;
public LocalDateTime dateTime;
LogItem(String userId, char eventChar) {
this.userId = userId;
this.eventChar = eventChar;
dateTime = LocalDateTime.now();
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public char getEventChar() {
return eventChar;
}
public void setEventChar(char eventChar) {
this.eventChar = eventChar;
}
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime(LocalDateTime dateTime) {
this.dateTime = dateTime;
}
#Override
public String toString() {
return "LogItem [userId=" + userId + ", eventChar=" + eventChar + ", dateTime=" + dateTime + ", getUserId()="
+ getUserId() + ", getEventChar()=" + getEventChar() + ", getDateTime()=" + getDateTime() + "]";
}
}
}
}
First, I would store the attributes in a Map<String,String>. This will make it easier to filter the attributes later. I am using a record in lieu of a class but a class would work as well.
record Person(String getName, String getAttribute) {
}
Create the list of Person objects
List<Person> list = List.of(new Person("bob", "V"),
new Person("bob", "A"), new Person("bob", "B"),
new Person("bob", "C"), new Person("bob", "C"),
new Person("sally", "B"), new Person("sally", "C"),
new Person("sally", "A"), new Person("steve", "A"),
new Person("steve", "B"), new Person("steve", "C"));
Now create the map. Simply stream the list of people and concatenate the attributes for each person.
Map<String, String> personMap = list.stream()
.collect(Collectors.toMap(Person::getName,
Person::getAttribute, String::concat));
The map will look like this.
bob=VABCC
steve=ABC
sally=BCA
Now grab the name based on an attribute string.
Now stream the entries of the map and pass the entry whose value contains the attribute string. Then retrieve the key (name) and return as a list of names.
String attributes = "ABC";
ListString> results = personMap.entrySet().stream()
.filter(e -> e.getValue().contains(attributes))
.map(Entry::getKey).collect(Collectors.toList());
System.out.println(results);
prints
[bob, steve]
Alternative approach using Map<String, List<String>>
Group the objects by name but the values will be a list of attributes instead of a string.
Map<String, List<String>> personMap = list.stream()
.collect(Collectors.groupingBy(Person::getName,
Collectors.mapping(Person::getAttribute,
Collectors.toList())));
The map will look like this.
bob=[V, A, B, C, C]
steve=[A, B, C]
sally=[B, C, A]
To facilitate testing the attributes, a BiPredicate is used to stream the list and concatinate the attributes and then check and see if it contains the attribute string.
BiPredicate<Entry<String, List<String>>, String> contains =
(entry, attr) -> entry.getValue().stream()
.collect(Collectors.joining()).contains(attr);
As before, stream the entry set of the map and apply the filter to pass those entries which satisfy the condition. In this case, the filter invokes the BiPredicate.
String attributes = "ABC";
List<String> results = personMap.entrySet().stream()
.filter(e->contains.test(e, attributes))
.map(Entry::getKey).collect(Collectors.toList());
System.out.println(results);
prints
[bob, steve]
Update Answer
To work with Character attributes, you can do the following using the first example.
Map<String, String> personMap2 = list.stream()
.collect(Collectors.toMap(Person::getName,
p -> Character.toString(p.getAttribute()),
String::concat));
Imo, it would be easier, if possible to change your attribute types to string.
I have two query and resultsets, in the below code I want to showcase that for a particular userGroupCode I have certain userPreference and employee associated with it. I have written the code below code to display the userGroupCode object:
String query1= "SELECT ug.userGroupCode, ug.userGroupDesc, up.userPreference"
+ "FROM dbo.UserGroup_link ug INNER JOIN dbo.UserPreference up ON ug.userGroupCode = up.userGroupCode";
userGroupCode
userGroupDesc
userPreference
A100
Finance
Mumbai
A100
Finance
Bangalore
A200
Supply Chain
Chennai
A201
Marketing
Delhi
A201
Marketing
Kolkata
A300
Health
Indore
String query2= "SELECT ug.userGroupCode, ug.userGroupDesc, emp.employee_id,emp.name,emp.role"
+ "FROM dbo.UserGroup ug INNER JOIN dbo.employee emp ON ug.userGroupCode = emp.userGroupCode";
userGroupCode
userGroupDesc
employee_id
name
role
A100
Finance
101
Foo1
Developer
A100
Finance
101
Foo1
Team Lead
A200
Supply Chain
091
Test1
Manager
A201
Marketing
591
User1
Analyst
A201
Marketing
1001
Boo1
Scrum Master
A300
Health
1001
Boo1
Developer
I have class UserGroupMapping like:
public class UserGroupMapping {
private String userGroupCode;
private String userGroupCode;
private List<String> userPreference;
private List<Employee> emp;
//getter and setter
}
Another class for Employee is:
public class Employee {
private String employee_id;
private String name;
private List<String> role;
//getter and setter
}
In my stored procedure class I am calling these queries with the help of jdbcTemplate.query();
String userCode = null;
List<String> userPreferenceList = new ArrayList<>();
List<UserGroupMapping> userGroupMappingList = new ArrayList<>();
List<UserGroupMapping> userGroupMappingList1 = new ArrayList<>();
UserGroupMapping userGroupMapping = new UserGroupMapping();
List<Employee> employeeList = new ArrayList<>();
Employee emp = new Employee();
UserGroupMapping userGroupMapping1 = new UserGroupMapping();
jdbcTemplate.query(query1, (rs)->{
String user_group_code = rs.getString("userGroupCode");
String user_group_desc = rs.getString("userGroupDesc");
String user_preference = rs.getString("userPreference");
if(userCode == null){
userGroupMapping.setUserGroupCode(user_group_code);
userGroupMapping.setUserGroupDesc(user_group_desc);
userPreferenceList.add(userPreference);
userCode = user_group_code;
} else if (userCode.equals(user_group_code)) {
userPreferenceList.add(userPreference);
} else {
userGroupMapping.setUserPreference(userPreferenceList);
userGroupMappingList.add(userGroupMapping);
userPreferenceList = new ArrayList<>();
userGroupMapping = new userGroupMapping();
userGroupMapping.setUserGroupCode(user_group_code);
userGroupMapping.setUserGroupDesc(user_group_desc);
userPreferenceList.add(userPreference);
userCode = user_group_code;
}});
userCode = null;
userGroupMapping.setUserPreference(userPreferenceList);
userGroupMappingList.add(userGroupMapping);
jdbcTemplate.query(query2, (rs)->{
String user_group_code = rs.getString("userGroupCode");
String user_group_desc = rs.getString("userGroupDesc");
String emp_id = rs.getString("employee_id");
String name = rs.getString("name");
if(userCode == null){
userGroupMapping1.setUserGroupCode(user_group_code);
userGroupMapping1.setUserGroupDesc(user_group_desc);
emp.setId(employeeId);
emp.setName(name);
employeeList.add(emp);
userCode = user_group_code;
} else if (userCode.equals(user_group_code)) {
Employee emp = new Employee();
emp.setId(employeeId);
emp.setName(name);
employeeList.add(emp);
} else {
userGroupMapping1.setEmployee(employeeList);
userGroupMappingList1.add(userGroupMapping1);
employeeList = new ArrayList<>();
userGroupMapping1 = new userGroupMapping();
Employee emp = new Employee();
userGroupMapping1.setUserGroupCode(user_group_code);
userGroupMapping1.setUserGroupDesc(user_group_desc);
emp.setId(employeeId);
emp.setName(name);
employeeList.add(emp);
userCode = user_group_code;
}});
userGroupMapping1.setEmployee(employeeList);
userGroupMappingList1.add(userGroupMapping1);
List<UserGroupMapping> ugList = Stream.concat(userGroupMappingList.stream, userGroupMappingList1.stream).distinct().collect(Collectors.toList())
return ugList;
The problem is that I want my output to be like :
[
{
"userGroupCode" : "A100",
"userGroupDesc" : "Finance",
"userPreference": ["Mumbai","Bangalore"],
"Employee" : [
"employee_id" : "101",
"name" : "Foo1",
"role" : ["Developer","Team Lead"]
]
}
]
After merging the two list I am getting the below output:
[
{
"userGroupCode" : "A100",
"userGroupDesc" : "Finance",
"userPreference": ["Mumbai","Bangalore"],
"Employee" : []
},
{
"userGroupCode" : "A100",
"userGroupDesc" : "Finance",
"userPreference": [],
"Employee" : [
"employee_id" : "101",
"name" : "Foo1",
"role" : []
]
}
]
Could anyone please help me with few things:
How could I embed the role into the Employee object.
How can I merge the table based on userGroupCode and userGroupDesc.
I am feeling the code is not that performance optimised, How could I optimised this code.
Thank you in advance.
Ola,
You can group by using Map taking id as key and value as object ( to be aggregated into) . For example:
if(map.containes(key))
{
get object from map and do Ops.
}
else
{
1. Create new object
2. Do set Ops on Object
3. Add to map.
}
You basically have 2 solutions,
Write a query that returns all results with joins and do filtering in java, quite easy to achieve with 2 maps (one for the UserGroup the other for the Employee.
Write a query and aggregate the duplicates using list in the query itself.
SELECT ug.userGroupCode, ug.userGroupDesc, up.userPreference, emp.employee_id,emp.name,emp.role
FROM dbo.UserGroup_link ug
INNER JOIN dbo.UserPreference up ON ug.userGroupCode = up.userGroupCode
INNER JOIN dbo.employee emp ON ug.userGroupCode = emp.userGroupCode
Then use a RowCallbackHandler to achieve what you want (instead of a ResultSetExtractor.
Map<String, UserGroup> userGroups = new HashMap<>;
Map<Integer, Employee> employees = new HashMap<>;
jdbc.query(query, (rs) -> {
String userGroupCode = rs.getString("userGroupCode");
String emp_id = rs.getString("employee_id");
UserGroupMapping ugm userGroups.computeIfAbsent(userGroupCode, {
UserGroupMapping ugm1 = new UserGroupMapping();
ugm1.setUserGroupCode(userGroupCode);
ugm1.setUserGroupDesc(rs.getString("userGroupDesc");
ugm1.setUserPreference(new ArrayList<>());
ugm1.getEmployee(new ArrayList<>());
return ugm1;
});
ugm.getUserPreference().add(rs.getString("userPreference"));
Employee emp = employees.computeIfAbsent(emp_id, {
Employee emp1 = new Employee();
emp1.setName(rs.getString("name"));
emp1.setRole(new ArrayList<>());
ugm.getEmployee().add(emp);
return emp1;
});
emp.getRole().add(rs.getString("role"));
});
return userGroups.values();
The above code will get all UserGroupMapping objects from the result including all the Employee instances. The temporary maps are needed to determine if record has already been shown.
Another solution would be to use list in your query and some GROUP BY statement to let the query do part of the aggregation. That way you could make it a bit easier to create an Employee.
I have following list of objects
class Account {
int id;
String type;
int balance;
Customer customer;
// getters setters
}
class Customer {
int customerID;
}
List<Account> accounts = new ArrayList<>();
accounts.add(new Account(1, "abc", 17998210, new Customer(190)));
accounts.add(new Account(2, "hsj", 6786179, new Customer(190)));
accounts.add(new Account(4, "ioip", 246179, new Customer(191)));
accounts.add(new Account(4, "ewrew", 90179, new Customer(191)));
I want to transfer above to Map and key should be the customerID and values should be list of Account
Map<Integer, List<Account>>
Key Value
190 -> Account(1, "abc", 17998210, 190)
Account(2, "hsj", 6786179, 190)
191 -> Account(4, "ioip", 246179, 191)
Account(4, "ewrew", 90179, 191)
How to achieve this?
You can use Collectors.groupingBy.
Map<Integer, List<Account>> map =
accounts.stream().collect(Collectors.groupingBy(Account::getCustomerID));
Demo
List<Account> accounts = new ArrayList<>();
accounts.add(new Account(1, "abc", 17998210, 190));
accounts.add(new Account(2, "hsj", 6786179, 190));
accounts.add(new Account(4, "ioip", 246179, 191));
accounts.add(new Account(4, "ewrew", 90179, 191));
Map<Integer, List<Account>> accountsMap = new HashMap<>();
for (Account account : accounts) {
accountsMap.computeIfAbsent(account.customerID, k -> new ArrayList<>()).add(account);
}
I would prefer to use the Collectors.toMap method with three parameters for clarity:
Map<Integer, List<Account>> map = accounts.stream()
.collect(Collectors.toMap(
// key - customerID
e -> e.getCustomer().getCustomerID(),
// value - List<Account>
e -> List.of(e),
// merge two lists
(l1, l2) -> Stream.of(l1, l2)
.flatMap(List::stream)
.collect(Collectors.toList())));
It is not printing anything there is no error.
kindly help me in resolving his error.
I have tried three methods to print but still not a single one is working and there isn't any error.
import java.util.ArrayList;
public class JavaEight {
public static void main(String args[])
{
ArrayList<Employee> Emp = new ArrayList<>();
Employee e1 = new Employee(101, "Ravi", "Delhi", "2000");
Employee e2 = new Employee(102, "Vineet", "Mangalore", "5000");
Employee e3 = new Employee(103, "Punit", "Mumbai", "3000");
Employee e4 = new Employee(104, "Shruti", "Banglore", "6000");
Employee e5 = new Employee(105, "Ritu", "Hyderabad", "8000");
for(int i=0; i<Emp.size();i++)
{
Employee e = (Employee)Emp.get(i);
System.out.println(e);
}
Emp.forEach(i -> System.out.println(Emp));
for(Employee i : Emp)
{
System.out.println(Emp);
}
}
}
emp.add(e1); etc is missing
you have created the employee objects, but you did not add them to the list. thus the list is blank, and not printing anything
add Employee in your ArrayList.
ArrayList<Employee> Emp = new ArrayList<>();
Employee e1 = new Employee(101, "Ravi", "Delhi", "2000");
Employee e2 = new Employee(102, "Vineet", "Mangalore", "5000");
Employee e3 = new Employee(103, "Punit", "Mumbai", "3000");
Employee e4 = new Employee(104, "Shruti", "Banglore", "6000");
Employee e5 = new Employee(105, "Ritu", "Hyderabad", "8000");
Emp.add(e1);
Emp.add(e2);
Emp.add(e3);
Emp.add(e4);
Emp.add(e5);
hope , it will resolve your issue.
This is because your ArrayList Emp is empty.
You have created the Employee object but you have not added it to Emp.
add it to Emp like Emp.add(e1).
I have the below results as part of resultset.
Name Dept
John IT
Mike IT
Cathy CS
Julie CS
Aria Electronics
Shann Electronics
I should be able to separate the resultset based on Dept and put the results in a map. E.g: After Mike, the dept changes and hence I should put John and Mike in a map. Then Cathy and Julie in a map and so on. How do I do it?
public void loadMap(ResultSet inputResultSet, MbGlobalMap inputTranslationObjMap) throws Exception {
String key = "";
List < dept > list = new ArrayList < dept > ();
while (inputResultSet.next()) {
String name = inputResultSet.getString(1);
String key = inputResultSet.getString(2);
dept d1 = new dept(name, key);
list.add(d1);
}
if (inputTranslationObjMap.containsKey(key)) {
inputTranslationObjMap.update(key, list);
} else {
inputTranslationObjMap.put(key, list);
}
}
Try something like this -
public void loadMap(ResultSet inputResultSet,
MbGlobalMap inputTranslationObjMap) throws Exception {
// String key = "";
List<dept> list = null;
while (inputResultSet.next()) {
String name = inputResultSet.getString(1);
String key = inputResultSet.getString(2);
// first check if the map has a list already.
if (inputTranslationObjMap.containsKey(key)) {
list = inputTranslationObjMap.get(key);
} else {
// No... add a new list to the map.
list = new ArrayList<dept>();
inputTranslationObjMap.put(key, list);
}
dept d1 = new dept(name, key);
list.add(d1);
}
}