How to get sorted paged map by pair conditions using java 8 threads

I have some Account model object with a list of fields, in the simple case with two fields String name and double margin

And I need to get the exact page of these accounts that exceeds the allowable limit, sorted by margin and name. Each entry must have a margin as a key, and an account as a value.

I made this minimal code example, but it seems that sorting doesn't work for me. So I port it to TreeMap, but it will require extra memory, and I hate it. You probably need to wait to fix this inside the threads and add the lost sorting by name in case of equal field

 @Data class Account { private final String name; private final double margin; private final static double MARGIN_LIMIT = 100; private final static int PAGE_SIZE = 3; private static Set<Account> accounts = new HashSet<>(); public static void main(String[] args) { accounts.add(new Account("user1", 200)); accounts.add(new Account("user2", 100)); accounts.add(new Account("user3", 150)); accounts.add(new Account("user4", 175)); accounts.add(new Account("user5", 75)); accounts.add(new Account("user6", 110)); Map<Double,Account> val = new TreeMap<Double,Account>(Comparator.reverseOrder()); val.putAll(getClientsForClosing(2)); System.out.println(val); } private static Map<Double, Account> getClientsForClosing(int page) { return accounts.stream() .filter(account -> account.getMargin() >= MARGIN_LIMIT) .sorted(Comparator.comparingDouble(Account::getMargin).reversed()) .skip(PAGE_SIZE * (page - 1)) .limit(PAGE_SIZE) .collect(Collectors.toMap(Account::getMargin, o -> o)); } } 
+5
source share
3 answers

Your question and solution are somehow contradictory, on the one hand, you are showing code sorting your entries into margin - which is double ; in this case there is an easier way:

 accounts.stream() .filter(account -> account.getMargin() >= MARGIN_LIMIT) .skip(PAGE_SIZE * (page - 1)) .limit(PAGE_SIZE) .collect(Collectors.groupingBy( Account::getMargin, () -> new TreeMap<Double, List<Account>>(Comparator.reverseOrder()), Collectors.toList())); 

If you want to sort both margin and name and still save the definition as Map<Double, List<Account>> , you will have to stick with LinkedHashMap :

 accounts.stream() .filter(account -> account.getMargin() >= MARGIN_LIMIT) .sorted(Comparator.comparingDouble(Account::getMargin) .reversed() .thenComparing(Comparator.comparing(Account::getName))) .skip(PAGE_SIZE * (page - 1)) .limit(PAGE_SIZE) .collect(Collectors.toMap( Account::getMargin, x -> { List<Account> list = new ArrayList<>(); list.add(x); return list; }, (left, right) -> { left.addAll(right); return left; }, LinkedHashMap::new)); 
+4
source

It seems to fix what you are looking for

 private static Map<Double, Account> getClientsForClosing(int page) { return accounts.stream() .filter(account -> account.getMargin() >= MARGIN_LIMIT) .sorted(Comparator.comparingDouble(Account::getMargin) .reversed().thenComparing(Comparator.comparing(Account::getName))) .skip(PAGE_SIZE * (page - 1)) .limit(PAGE_SIZE) .collect(Collectors.toMap(Account::getMargin, o -> o, (oldVal, newVal) -> oldVal, LinkedHashMap::new)); } 
+4
source

Other answers are correct, however I think TreeSet (instead of TreeMap ) can help you:

 TreeSet<Account> accounts = new TreeSet<>( Comparator.comparingDouble(Account::getMargin).reversed() .thenComparing(Account::getName)); // Then add all the accounts Map<Double, List<Account>> result = accounts .headSet(new Account("zzzz", MARGIN_LIMIT)) // zzzz is the greatest string .stream() // I could think of at this time .skip(PAGE_SIZE * (page - 1)) // (it quite late here) .limit(PAGE_SIZE) .collect(Collectors.groupingBy(Account::getMargin)); 

This solution uses the TreeSet.headSet method, which fits like a glove for what you are trying to do. Then we go to the stream to skip and restrict the elements and finally collect the required data structure.

+2
source

Source: https://habr.com/ru/post/1273372/


All Articles