2
Iterator<Rate> rateIt = rates.iterator();
int lastRateOBP = 0;
while (rateIt.hasNext())
{
    Rate rate = rateIt.next();
    int currentOBP = rate.getPersonCount();
    if (currentOBP == lastRateOBP)
    {
        rateIt.remove();
        continue;
    }

    lastRateOBP = currentOBP;
}

how can i use above code convert to lambda by stream of java 8? such as list.stream().filter().....but i need to operation list.

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Haven Lin
  • 176
  • 1
  • 16
  • are you trying to remove duplicates from the list? – Anton Balaniuc May 15 '17 at 07:54
  • @AntonBalaniuc yep, i need to sort list, an then remove duplicates – Haven Lin May 15 '17 at 08:02
  • @HavenLin the way you have it right now is not removing duplicates in the `entire list`; it's removing those that follow only. For example you have this `5,5,6,7,7,8,5` what is the expect result in this case? `5,6,7,8,5` or `5,6,7,8` – Eugene May 15 '17 at 08:17
  • please look at this question - http://stackoverflow.com/questions/29670116/remove-duplicates-from-a-list-of-objects-based-on-property-in-java-8 – Anton Balaniuc May 15 '17 at 08:17

3 Answers3

4

The simplest solution is

Set<Integer> seen = new HashSet<>();
rates.removeIf(rate -> !seen.add(rate.getPersonCount()));

it utilizes the fact that Set.add will return false if the value is already in the Set, i.e. has been already encountered. Since these are the elements you want to remove, all you have to do is negating it.

If keeping an arbitrary Rate instance for each group with the same person count is sufficient, there is no sorting needed for this solution.

Like with your original Iterator-based solution, it relies on the mutability of your original Collection.

Holger
  • 285,553
  • 42
  • 434
  • 765
2

If you really want distinct and sorted as you say in your comments, than it is as simple as :

TreeSet<Rate> sorted = rates.stream()
                  .collect(Collectors.toCollection(() -> 
                   new TreeSet<>(Comparator.comparing(Rate::getPersonCount))));

But notice that in your example with an iterator you are not removing duplicates, but only duplicates that are continuous (I've exemplified that in the comment to your question).

EDIT

It seems that you want distinct by a Function; or in simpler words you want distinct elements by personCount, but in case of a clash you want to take the max pos.

Such a thing is not yet available in jdk. But it might be, see this.

Since you want them sorted and distinct by key, we can emulate that with:

 Collection<Rate> sorted = rates.stream()
            .collect(Collectors.toMap(Rate::getPersonCount,
                    Function.identity(),
                    (left, right) -> {
                        return left.getLos() > right.getLos() ? left : right;
                    },
                    TreeMap::new))
            .values();

    System.out.println(sorted);

On the other hand if you absolutely need to return a TreeSet to actually denote that this are unique elements and sorted:

 TreeSet<Rate> sorted = rates.stream()
            .collect(Collectors.collectingAndThen(

                    Collectors.toMap(Rate::getPersonCount,
                            Function.identity(),
                            (left, right) -> {
                                return left.getLos() > right.getLos() ? left : right;
                            },
                            TreeMap::new),
                    map -> {
                        TreeSet<Rate> set = new TreeSet<>(Comparator.comparing(Rate::getPersonCount));
                        set.addAll(map.values());
                        return set;
                    }));
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • i used your code to test, but it has a bit difference. Sample List as below: `Rate{ PersonCount:1, LOS:1} Rate{ PersonCount:1, LOS:2} Rate{ PersonCount:1, LOS:3} Rate{ PersonCount:2, LOS:1} Rate{ PersonCount:2, LOS:2} Rate{ PersonCount:2, LOS:3} Rate{ PersonCount:3, LOS:2} Rate{ PersonCount:4, LOS:3}` **My expected**: `Rate{ PersonCount:1, LOS:3} Rate{ PersonCount:2, LOS:3} Rate{ PersonCount:3, LOS:2} Rate{ PersonCount:4, LOS:3}`, **your code return**: `Rate{ PersonCount:1, LOS:1} Rate{ PersonCount:2, LOS:1} Rate{ PersonCount:3, LOS:2} Rate{ PersonCount:4, LOS:3}` – Haven Lin May 15 '17 at 09:51
  • yes, my meaning is just as you said "in simpler words you want distinct elements by personCount, but in case of a clash you want to take the max Los", but above code have expression error – Haven Lin May 16 '17 at 06:24
  • 1
    @HavenLin it's impossible for me to tell what those errors are... plz provide them – Eugene May 16 '17 at 06:48
  • sorry, it works well now~ this is my expected. thanks~ – Haven Lin May 16 '17 at 07:07
  • hi Engene, if i use `rates.stream().collect(groupingBy(Rate::getPersonCount))`, and then return Map>, and result is `[[Rate{ PersonCount:1, LOS:1}, Rate{ PersonCount:1, LOS:2}, Rate{ PersonCount:1, LOS:3}], [Rate{ PersonCount:2, LOS:1}, Rate{ PersonCount:2, LOS:2}, Rate{ PersonCount:2, LOS:3}], [Rate{ PersonCount:3, LOS:2}], [Rate{ PersonCount:4, LOS:3}]]`, have there simple a way to get max LOS for each value in this map? – Haven Lin May 16 '17 at 11:47
  • i post new question: http://stackoverflow.com/questions/44003534/how-can-i-get-value-from-list – Haven Lin May 16 '17 at 13:57
1

This should work if your Rate type has natural ordering (i.e. implements Comparable):

List<Rate> l = rates.stream()
                             .distinct()
                             .sorted()
                             .collect(Collectors.toList());

If not, use a lambda as a custom comparator:

List<Rate> l = rates.stream()
                             .distinct()
                             .sorted( (r1,r2) -> ...some code to compare two rates... )
                             .collect(Collectors.toList());

It may be possible to remove the call to sorted if you just need to remove duplicates.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • `compareTo` should be implemented in such a way that *same* `personCount` and *different* `los` will report different entries (result will be `!=0`). So the use of `distinct` will have no effect, it will still take all entries... What you want is distinct by a Function here – Eugene May 15 '17 at 12:26