I have an Employee Object, with in it Department Object. I need to sort by Employee Object Fields and then by Department Fields too. Data looks like below.
public static List getEmployeeData() {
Department account = new Department("Account", 75);
Department hr = new Department("HR", 50);
Department ops = new Department("OP", 25);
Department tech = new Department("Tech", 150);
List<Employee> employeeList = Arrays.asList(new Employee("David", 32, "Matara", account),
new Employee("Brayan", 25, "Galle", hr), new Employee("JoAnne", 45, "Negombo", ops),
new Employee("Jake", 65, "Galle", hr), new Employee("Brent", 55, "Matara", hr),
new Employee("Allice", 23, "Matara", ops), new Employee("Austin", 30, "Negombo", tech),
new Employee("Gerry", 29, "Matara", tech), new Employee("Scote", 20, "Negombo", ops),
new Employee("Branden", 32, "Matara", account), new Employee("Iflias", 31, "Galle", hr));
return employeeList;
}
I want to sort by Employee::name, Employee::Age, Department::DepartmentName how it can be sorted?
This should led to the desired result:
List<Employee> employees = getEmployeeData()
.stream()
.sorted(Comparator
.comparing(Employee::getName)
.thenComparing(Employee::getAge)
.thenComparing(e -> e.getDepartment().getName()))
.collect(Collectors.toList());
Related
I have a list of Employee
public class Employee {
private String name;
private Integer age;
private Double salary;
private Department department;
}
List<Employee> employeeList = Arrays.asList(
new Employee("Tom Jones", 45, 12000.00,Department.MARKETING),
new Employee("Harry Major", 26, 20000.00, Department.LEGAL),
new Employee("Ethan Hardy", 65, 30000.00, Department.LEGAL),
new Employee("Nancy Smith", 22, 15000.00, Department.MARKETING),
new Employee("Catherine Jones", 21, 18000.00, Department.HR),
new Employee("James Elliot", 58, 24000.00, Department.OPERATIONS),
new Employee("Frank Anthony", 55, 32000.00, Department.MARKETING),
new Employee("Michael Reeves", 40, 45000.00, Department.OPERATIONS));
I want to get Map<Employee, List<Employee>> where map key is for each Department's max salary employee and value is all employee of that department.
I am trying to groupingBy but it gives all employee with Department map. How to get all max salary employee as map key ?
Map<Department,List<Employee>> employeeMap
= employeeList.stream().collect(Collectors.groupingBy(Employee::getDepartment));
You can get the required result as follows:
Map<Employee, List<Employee>> result = employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary).reversed())
.collect(groupingBy(Employee::getDepartment, LinkedHashMap::new, toList())).values().stream()
.collect(toMap(l -> l.get(0), Function.identity()));
There's probably better and more efficient solutions out there and I would have exhausted those ideas had i not been on my phone.
This seems to work.
It first determines the employees by department then
Then it groups them based on the largest salary of the departments employee
Map<Employee, List<Employee>> map = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getDepartment))
.entrySet().stream()
.collect(Collectors.toMap(
e->e.getValue().stream()
.max(Comparator.comparing(
Employee::getSalary))
.get(),
Entry::getValue));
Overriding toString in Employee class to return name, salary, and department,
here is the output.
map.forEach((k,v)->{System.out.println(k);
for (Employee e: v) {
System.out.printf(" %s%n", e);
}
System.out.println();
});
Prints
Frank Anthony, 32000.0, MARKETING}
{Tom Jones, 12000.0, MARKETING}
{Nancy Smith, 15000.0, MARKETING}
{Frank Anthony, 32000.0, MARKETING}
{Michael Reeves, 45000.0, OPERATIONS}
{James Elliot, 24000.0, OPERATIONS}
{Michael Reeves, 45000.0, OPERATIONS}
{Catherine Jones, 18000.0, HR}
{Catherine Jones, 18000.0, HR}
{Ethan Hardy, 30000.0, LEGAL}
{Harry Major, 20000.0, LEGAL}
{Ethan Hardy, 30000.0, LEGAL}
You can do this:
Map<Employee, List<Employee>> employeeMap = employeeList.stream()
.collect(groupingBy(Employee::getDepartment))
.values().stream()
.collect(
groupingBy(
(es) -> es.stream()
.max(Comparator.comparing(e -> e.getSalary())).get()
)
).entrySet().stream()
.collect(toMap(
Map.Entry::getKey,
e -> e.getValue().iterator().next()
));
Output:
{(Michael Reeves, 40, 45000.0, OPERATIONS)=[(James Elliot, 58, 24000.0, OPERATIONS), (Michael Reeves, 40, 45000.0, OPERATIONS)],
(Catherine Jones, 21, 18000.0, HR)=[(Catherine Jones, 21, 18000.0, HR)],
(Ethan Hardy, 65, 30000.0, LEGAL)=[(Harry Major, 26, 20000.0, LEGAL), (Ethan Hardy, 65, 30000.0, LEGAL)],
(Frank Anthony, 55, 32000.0, MARKETING)=[(Tom Jones, 45, 12000.0, MARKETING), (Nancy Smith, 22, 15000.0, MARKETING), (Frank Anthony, 55, 32000.0, MARKETING)]}
Link to repl.it: https://repl.it/repls/CluelessAwesomeLevel#Main.java
I have this Object:
QuoteProductDTO with three columns ( name, value1, value2)
List<QuoteProductDTO> lstQuoteProductDTO = new ArrayList<>();
lstQuoteProductDTO.add( new QuoteProductDTO("product", 10, 15.5) );
lstQuoteProductDTO.add( new QuoteProductDTO("product", 05, 2.5) );
lstQuoteProductDTO.add( new QuoteProductDTO("product", 13, 1.0) );
lstQuoteProductDTO.add( new QuoteProductDTO("product", 02, 2.0) );
I need to get a consolidate ( a new object QuoteProductDTO ):
the firts column name,I have to get the first value "product".
the second one (value1) I have to get the biggest value 13.
and third column I heve to get the sum of all values 20.
This takes the current data provided and generates a new object with the required data. It uses the Collectors.teeing() method of Java 12+
Given the following data:
ArrayList<QuoteProductDTO> lstQuoteProductDTO = new ArrayList<>();
ArrayList<QuoteProductDTO> nextQuoteProductDTO = new ArrayList<>();
// empty Quote for Optional handling below.
QuoteProductDTO emptyQuote = new QuoteProductDTO("EMPTY", -1, -1);
lstQuoteProductDTO.add(
new QuoteProductDTO("Product", 10, 15.5));
lstQuoteProductDTO.add(
new QuoteProductDTO("Product", 05, 2.5));
lstQuoteProductDTO.add(
new QuoteProductDTO("Product", 13, 1.0));
lstQuoteProductDTO.add(
new QuoteProductDTO("Product", 02, 2.0));
You can consolidate like you want into a new instance of QuoteProductDTO.
QuoteProductDTO prod = lstQuoteProductDTO.stream()
.collect(Collectors.teeing(
Collectors.maxBy(Comparator
.comparing(p -> p.value1)),
Collectors.summingDouble(
p -> p.value2),
(a, b) -> new QuoteProductDTO(
a.orElse(emptyQuote).name,
a.orElse(emptyQuote).value1,
b.doubleValue())));
System.out.println(prod);
Prints
Product, 13, 21.0
You can also take a list of lists of different products and put them in a list of consolidated products. Add the following to a new list and then add those to a main list.
nextQuoteProductDTO.add(
new QuoteProductDTO("Product2", 10, 15.5));
nextQuoteProductDTO.add(
new QuoteProductDTO("Product2", 25, 20.5));
nextQuoteProductDTO.add(
new QuoteProductDTO("Product2", 13, 1.0));
nextQuoteProductDTO.add(
new QuoteProductDTO("Product2", 02, 2.0));
List<List<QuoteProductDTO>> list = List.of(
lstQuoteProductDTO, nextQuoteProductDTO);
Now consolidate those into a list of objects.
List<QuoteProductDTO> prods = list.stream().map(lst -> lst.stream()
.collect(Collectors.teeing(
Collectors.maxBy(Comparator
.comparing(p -> p.value1)),
Collectors.summingDouble(
p -> p.value2),
(a, b) -> new QuoteProductDTO(
a.orElse(emptyQuote).name,
a.orElse(emptyQuote).value1,
b.doubleValue()))))
.collect(Collectors.toList());
prods.forEach(System.out::println);
Prints
Product, 13, 21.0
Product2, 25, 39.0
I created a class to help demonstrate this.
class QuoteProductDTO {
public String name;
public int value1;
public double value2;
public QuoteProductDTO(String name, int value1,
double value2) {
this.name = name;
this.value1 = value1;
this.value2 = value2;
}
public String toString() {
return name + ", " + value1 + ", " + value2;
}
}
I have the following piece of code
OrderCriteria o1 = new OrderCriteria(1, 1, 101, 201);
OrderCriteria o2 = new OrderCriteria(1, 1, 102, 202);
OrderCriteria o4 = new OrderCriteria(1, 1, 102, 201);
OrderCriteria o5 = new OrderCriteria(2, 2, 501, 601);
OrderCriteria o6 = new OrderCriteria(2, 2, 501, 602);
OrderCriteria o7 = new OrderCriteria(2, 2, 502, 601);
OrderCriteria o8 = new OrderCriteria(2, 2, 502, 602);
OrderCriteria o9 = new OrderCriteria(2, 2, 503, 603);
Where OrderCriteria looks like below:
public class OrderCriteria {
private final long orderId;
private final long orderCatalogId;
private final long procedureId;
private final long diagnosisId;
public OrderCriteria(long orderId, long orderCatalogId, long procedureId, long diagnosisId) {
this.orderId = orderId;
this.orderCatalogId = orderCatalogId;
this.procedureId = procedureId;
this.diagnosisId = diagnosisId;
}
// Getters
}
What I want is to get a list of procedures and list of diagnosis grouped by order id. So it should return:
{1, {101, 102}, {201, 202}}
{2, {501, 502, 503}, {601, 602, 603}}
which means Order with id 1 is having procedure ids 101, 102 and diagnosis ids 201, 202 etc. I tried using google guava table but could not come up with any valid solution.
First you'll need a new structure to hold the grouped data:
class OrderCriteriaGroup {
final Set<Long> procedures = new HashSet<>();
final Set<Long> diagnoses = new HashSet<>();
void add(OrderCriteria o) {
procedures.add(o.getProcedureId());
diagnoses.add(o.getDiagnosisId());
}
OrderCriteriaGroup merge(OrderCriteriaGroup g) {
procedures.addAll(g.procedures);
diagnoses.addAll(g.diagnoses);
return this;
}
}
add() and merge() are convenience methods that will help us stream and collect the data, like so:
Map<Long, OrderCriteriaGroup> grouped = criteriaList.stream()
.collect(Collectors.groupingBy(OrderCriteria::getOrderId,
Collector.of(
OrderCriteriaGroup::new,
OrderCriteriaGroup::add,
OrderCriteriaGroup::merge)));
I highly recommend you to change the output structure. The current, according to your example is probably Map<List<Set<Long>>>. I suggest you distinguish between "procedure: and "diagnosis" set of data using the following structure:
Map<Long, Map<String, Set<Long>>> map = new HashMap<>();
Now filling the data is quite easy:
for (OrderCriteria oc: list) {
if (map.containsKey(oc.getOrderId())) {
map.get(oc.getOrderId()).get("procedure").add(oc.getProcedureId());
map.get(oc.getOrderId()).get("diagnosis").add(oc.getDiagnosisId());
} else {
Map<String, Set<Long>> innerMap = new HashMap<>();
innerMap.put("procedure", new HashSet<>());
innerMap.put("diagnosis", new HashSet<>());
map.put(oc.getOrderId(), innerMap);
}
}
Output: {1={diagnosis=[201, 202], procedure=[102]}, 2={diagnosis=[601, 602, 603], procedure=[501, 502, 503]}}
If you insist on the structure you have drafted, you would have to remember that the first Set contains procedures and the second one contains the diagnosis and the maintenaince would be impractical.
Map<Long, List<Set<Long>>> map = new HashMap<>();
for (OrderCriteria oc: list) {
if (map.containsKey(oc.getOrderId())) {
map.get(oc.getOrderId()).get(0).add(oc.getProcedureId());
map.get(oc.getOrderId()).get(1).add(oc.getDiagnosisId());
} else {
List<Set<Long>> listOfSet = new ArrayList<>();
listOfSet.add(new HashSet<>());
listOfSet.add(new HashSet<>());
map.put(oc.getOrderId(), listOfSet);
}
}
Output: {1=[[102], [201, 202]], 2=[[501, 502, 503], [601, 602, 603]]}
Alternatively you might want to create a new object with 2 Set<Long> to store the data instead (another answer shows the way).
I'm trying to read lines from file into Arraylist. Here is my writer :
private Map<Integer, ArrayList<Integer>> motPage =
new HashMap<Integer, ArrayList<Integer>>();
private void writer() throws UnsupportedEncodingException, FileNotFoundException, IOException{
try (Writer writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("/home/kdiri/workJuno/motorRecherche/src/kemal.txt"), "utf-8"))) {
for(Map.Entry<Integer, ArrayList<Integer>> entry : motPage.entrySet()){
writer.write(entry.getKey() + " : " + entry.getValue() + "\n");
}
}
}
And this is an exemple result in the file kemal.txt :
0 : [38, 38, 38, 38, 199, 199, 199, 199, 3004, 3004, 3004, 3004, 23, 23]
My question is how can I read it these lines efficiently into Hashmap again ? Because size of file is about 500MB. Thank you in advance.
As JonSkeet said, you should start with something working. Find below one possible way. The snippet is kept quite verbose to show the principle.
String line = "0 : [38, 38, 38, 38, 199, 199, 199, 199, 3004, 3004, 3004, 3004,
23, 23]";
int firstSpace = line.indexOf(" ");
int leftSquareBracket = line.indexOf("[");
int rightSquareBracket = line.indexOf("]");
String keyString = line.substring(0, firstSpace);
String[] valuesString = line.substring(leftSquareBracket + 1, rightSquareBracket)
.split(", ");
int key = new Integer(keyString);
List<Integer> values = new ArrayList<>(valuesString.length);
for (String value : valuesString) {
values.add(new Integer(value));
}
Map<Integer, List<Integer>> motPage = new HashMap<>();
motPage.put(key, values);
Btw. read ... these lines efficiently into Hashmap depends on your requirements. Efficiency could be for example:
read speed of the huge file
convertion speed String to Integer
small size of the bytecode
less object generation
... there could be other as well
When the snippet does not fulfil your efficiency criteria. Start to tune the part which impacts your criteria.
I need to create a Class CustApp that:
Creates a Customer object, a Customer variable named c, and assigns
the object to c.
Set values for Customer properties.
Creates a CustFrame object and passes the Customer variable c.
Creates a CustFrame variable named cf, assigns the CustFrame object
to cf.
So far I have this code, but I can't figure out how to define the properties.
public class CustApp {
public static void main(String[] args) {
Customer c = new Customer();
c.setBounds(62, 65, 176, 23);
c.setBounds(62, 120, 176, 23);
c.setBounds(62, 175, 176, 23);
c.setBounds(62, 230, 176, 23);
c.setText(c.getCustName());
c.setText(c.getShipToStreet());
c.setText(c.getShipToCity() + ", " + c.getShipToState() + " " + c.getShipToZip());
c.setText(c.getContactPerson() + " Ph: " + c.getContactPhone());
CustFrame cf = new CustFrame(c);
}
}