如何排列对象集合

时间:2017-01-11 21:04:00

标签: java java-8 java-stream collectors

我有课,例如

class Person{
    Integer rank;
    Double profit;
    Person(Integer rank, Double profit){
        this.rank = rank;
        this.profit = profit;
    }
    Person(Double profit){
        this(0, profit);
    }
}

我想按排名评估对按利润人排序的列表进行排名。 那么

rank(Arrays.asList(
    new Person(30), 
    new Person(20), 
    new Person(20), 
    new Person(10))
)

将生成列表

new Person(1, 30), 
new Person(2, 20), 
new Person(2, 20), 
new Person(3, 10)

此外,我想使用Java 8中的自定义Collector(或类似的东西)来做,而不是使用简单的循环。

2 个答案:

答案 0 :(得分:2)

你可以这样做:

  1. 首先使用自定义Comparator;
  2. 对列表进行排序
  3. 使用没有重复的利润创建新列表(distinct()方法);
  4. 使用forEach()设置适当的排名。
  5. 我希望它会有所帮助。

    List<Person> l  = Arrays.asList(new Person(30.0), new Person(20.0), new Person(20.0), new Person(10.0));
    Collections.sort(l,(Person o1, Person o2)->o1.profit.compareTo(o2.profit));
    List<Double> p = l.stream().map(a -> a.profit).distinct().collect(Collectors.toList());
    l.forEach(a -> a.setRank(p.indexOf(a.profit) + 1));
    

答案 1 :(得分:2)

让我们使用一个自定义收集器,我们从外面传递所有东西。收集器将从调用者获得排名和构造函数。我们想这样称呼:

public class IntegerRankingCollector<T> implements Collector<T, List<T>, List<T>> {
        ...

    public IntegerRankingCollector(Comparator<? super T> comparator, Function<T, Integer> ranker, BiFunction<T, Integer, T> creator) {
        this.comparator = comparator;
        this.ranker = ranker;
        this.creator = creator;
    }

    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return (list, current) -> {
            ArrayList<T> right = new ArrayList<>();
            right.add(creator.apply(current, 1));
            combiner().apply(list, right);
        };
    }

    @Override
    public BinaryOperator<List<T>> combiner() {
        return (left, right) -> {
            int rankAdjustment = getRankAdjustment(left, right);
            for (T t : right)
                left.add(creator.apply(t, rankAdjustment + ranker.apply(t)));
            return left;
        };
    }

    private int getRankAdjustment(List<T> left, List<T> right) {
        Optional<T> lastElementOnTheLeft = optGet(left, left.size() - 1);
        Optional<T> firstElementOnTheRight = optGet(right, 0);

        if (!lastElementOnTheLeft.isPresent() || !firstElementOnTheRight.isPresent())
            return 0;
        else if (comparator.compare(firstElementOnTheRight.get(), lastElementOnTheLeft.get()) == 0)
            return ranker.apply(lastElementOnTheLeft.get()) - 1;
        else
            return ranker.apply(lastElementOnTheLeft.get());
    }

    private Optional<T> optGet(List<T> list, int index) {
        if (list == null || list.isEmpty())
            return Optional.empty();
        else
            return Optional.of(list.get(index));
    }

        ...
    }

此收集器可以像Collectors.toList()一样实现,但使用累加器方法:

  1. 获取前一个元素的排名
  2. 如果当前元素排名应该不同,则
  3. 增加它 上一个要素等级
  4. 使用新等级
  5. 创建一个元素

    以下是它的外观,它应该适用于有序流:

    Collectors.toList

    为了完整性,这是该类的完整代码。我从public class IntegerRankingCollector<T> implements Collector<T, List<T>, List<T>> { private static final Set<Characteristics> CHARACTERISTICSS = Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); private Comparator<? super T> comparator; private BiFunction<T, Integer, T> creator; private Function<T, Integer> ranker; public IntegerRankingCollector(Comparator<? super T> comparator, Function<T, Integer> ranker, BiFunction<T, Integer, T> creator) { this.comparator = comparator; this.ranker = ranker; this.creator = creator; } @Override public BiConsumer<List<T>, T> accumulator() { return (list, current) -> { ArrayList<T> right = new ArrayList<>(); right.add(creator.apply(current, 1)); combiner().apply(list, right); }; } @Override public BinaryOperator<List<T>> combiner() { return (left, right) -> { int rankAdjustment = getRankAdjustment(left, right); for (T t : right) left.add(creator.apply(t, rankAdjustment + ranker.apply(t))); return left; }; } private int getRankAdjustment(List<T> left, List<T> right) { Optional<T> lastElementOnTheLeft = optGet(left, left.size() - 1); Optional<T> firstElementOnTheRight = optGet(right, 0); if (!lastElementOnTheLeft.isPresent() || !firstElementOnTheRight.isPresent()) return 0; else if (comparator.compare(firstElementOnTheRight.get(), lastElementOnTheLeft.get()) == 0) return ranker.apply(lastElementOnTheLeft.get()) - 1; else return ranker.apply(lastElementOnTheLeft.get()); } private Optional<T> optGet(List<T> list, int index) { if (list == null || list.isEmpty()) return Optional.empty(); else return Optional.of(list.get(index)); } @Override public Supplier<List<T>> supplier() { return ArrayList::new; } @Override public Function<List<T>, List<T>> finisher() { return l -> l; } @Override public Set<Characteristics> characteristics() { return CHARACTERISTICSS; } } 复制了其余的内容:

    {{1}}