2017-01-11 5 views
2

私は例オブジェクトのコレクションをランク付けする方法

私はランク評価の利益の人々によってソートされたリストをランク付けしたい
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(または同様のもの)を使用していないことをやりたいです。

+0

「Comparator」を使って簡単に実行できます。 Javaの 'Comparator&Comparable'についてもっと読む:https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html – user2004685

+0

@ user2004685 with' Comparator'私のコレクションをソートすることができますどのようにランクを要素に設定できますか? –

+0

あなたの例は私には意味がありません。単一のパラメータコンストラクタがランクを '0'に設定するので、' Person'オブジェクトはソート時にどのように魔法のようにランク付けされますか? – azurefrog

答えて

1

外部からすべてのものを渡すカスタムコレクターを使用しましょう。コレクターは、呼び出し元からランキングとコンストラクターを取得します。我々はこのようにそれを呼び出すしたいと思います:

public List<Person> rank(List<Person> people) { 
     return people 
       .stream() 
       .sorted(Comparator.<Person>comparingDouble(x -> x.profit).reversed()) 
       .collect(new IntegerRankingCollector<>(
         Comparator.comparingDouble(p -> p.profit), // how to differentiate rankings 
         p -> p.rank, // where to get rank for an element which was already ranked 
         (p, rank) -> new Person(rank, p.profit)  // how to create an element from another element values and a rank 
       )); 
    } 

このコレクターはCollectors.toList()ようですが、アキュムレータの方法で実装することができます。

  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からコピーしました。

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

あなたはこのようにそれを行うことができます。

  1. まずカスタムComparatorでリストを並べ替えます。
  2. 重複のない利益で新しいリストを作成する(distinct()メソッド)。
  3. は、forEach()を使用して適切なランクに設定されます。

私はそれが役に立ちそうです。

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)); 
+0

あなたのアルゴリズムは非常に効果がありません。最後の行には二次的な複雑さがあります。そして、あなたが同じ.equals()結果を持つリストオブジェクトを保持していると、間違った順位付けをすることさえあります。 – JiangHongTiao

関連する問題