2015-01-12 4 views
14

У меня есть поток, такой как:Java8 Streams - Удаление дубликатов с потоком Distinct

Arrays.stream(new String[]{"matt", "jason", "michael"}); 

Я хотел бы, чтобы удалить имена, которые начинаются с той же буквы, так что только одно имя (не имеет значения, какой) начинает с этой буквой осталось.

Я пытаюсь понять, как работает метод distinct(). Я прочитал в документации, что он основан на методе «равно» объекта. Однако, когда я пытаюсь обернуть String, я замечаю, что метод equals никогда не вызывается и ничего не удаляется. Здесь что-то не хватает?

Упаковочный Класс:

static class Wrp { 
    String test; 
    Wrp(String s){ 
     this.test = s; 
    } 
    @Override 
    public boolean equals(Object other){ 
     return this.test.charAt(0) == ((Wrp) other).test.charAt(0); 
    } 
} 

И некоторые простой код:

public static void main(String[] args) { 
    Arrays.stream(new String[]{"matt", "jason", "michael"}) 
    .map(Wrp::new) 
    .distinct() 
    .map(wrp -> wrp.test) 
    .forEach(System.out::println); 
} 
+2

Там в метод, который я описал в [этот ответ] (http://stackoverflow.com/a/27872086/1441122). (Прокрутите до конца ответа). Это позволит вам выполнить фильтрацию (distinctByKey (s -> s.charAt (0))). –

+6

Замечание: для потока литералов часто проще использовать 'Stream.of (« матовый »,« jason »,« michael »)'. –

ответ

14

Всякий раз, когда вы переопределить equals, вам также необходимо переопределить hashCode() метод, который будет использоваться при осуществлении distinct().

В этом случае, вы могли бы просто использовать

@Override public int hashCode() { 
    return test.charAt(0); 
} 

..., который будет работать нормально.

+5

Да, похоже, это работает. Было бы неплохо, если бы вы могли передать компаратора в «отдельный», чтобы сделать это немного легче. –

+4

Если это то, что вы хотите, вы можете просто свалить его в «TreeSet». –

+5

Вы правы ... Иногда, когда вы получаете новый молоток, все начинает выглядеть как гвоздь. ;-) –

5

Альтернативный подход

String[] array = {"matt", "jason", "michael"}; 
    Arrays.stream(array) 
      .map(name-> name.charAt(0)) 
      .distinct() 
      .map(ch -> Arrays.stream(array).filter(name->name.charAt(0) == ch).findAny().get()) 
      .forEach(System.out::println);