如何使用java 8流通过耦合条件获取已排序的分页映射

时间:2017-11-14 21:37:15

标签: java java-8 java-stream

我有一些带有字段列表的模型对象Account,简单来说就是两个字段String namedouble margin

我需要获得这个帐户的确切页面超过一定的保证金限制,按保证金和&名称。每条记录都应该有保证金作为关键,而账户作为价值。

我制作了这个代码的最小例子,但似乎排序并不适合我。所以我将它包装在TreeMap中,但它会耗费额外的内存,我讨厌它。 可能应该等待在流内部修复此问题并在等于保证金的情况下按名称添加丢失的排序

@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));
    }
}

3 个答案:

答案 0 :(得分:4)

似乎确切地解决了您正在寻找的问题

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));
}

答案 1 :(得分:4)

您的问题和解决方案在某种程度上是矛盾的,一方面您会显示按margin对您的条目进行排序的代码 - 这是double;在这种情况下,有一种更简单的方法:

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()));

如果您希望按 marginname进行排序,并且仍将定义保持为Map<Double, List<Account>>,则必须坚持使用{{1 }}:

LinkedHashMap

答案 2 :(得分:2)

其他答案都是正确的,但我认为TreeSet(而不是TreeMap)对您有很大的帮助:

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's quite late here)
    .limit(PAGE_SIZE)
    .collect(Collectors.groupingBy(Account::getMargin));

此解决方案使用TreeSet.headSet方法,它适合您尝试做的手套。然后,我们转向流以跳过并限制元素,最后收集到所需的数据结构。