2015-10-05 2 views
3

Учитывая следующий пример, я хотел бы функцию потока, которая сортирует список, а также вложенный списокJava 8 Streams - Сортировка вложенных списков иерархически

class Foo { 
    public int sort; 
    public List<Bar> bars; 
    public Foo(int sort) { 
     this.sort = sort; 
    } 

} 

class Bar { 
    public int sort; 

    public Bar(int sort) { 
     this.sort = sort; 
    } 
} 

@Test 
public void testSortering() { 
    Foo foo = new Foo(1); 
    Foo foo2 = new Foo(2); 
    Bar bar = new Bar(1); 
    Bar bar2 = new Bar(2); 
    foo.bars = Arrays.asList(bar2, bar); 
    foo2.bars = Arrays.asList(bar2, bar); 

    List<Foo> foos = Arrays.asList(foo2, foo); 

    //I would like to iterate foos and return a new foos sorted, and with bars sorted, so that this goes green 

    assertEquals(1, foos.get(0).sort); 
    assertEquals(1, foos.get(0).bars.get(0).sort); 
    assertEquals(2, foos.get(0).bars.get(1).sort); 
    assertEquals(2, foos.get(1).sort); 
    assertEquals(1, foos.get(1).bars.get(0).sort); 
    assertEquals(2, foos.get(1).bars.get(1).sort); 

} 

Я попытался это:

List<List<Bar>> foosSorted = foos.stream() 
     .sorted((o1, o2) -> Integer.compare(o1.sort, o2.sort)) 
     .map(f -> f.bars.stream().sorted((o1, o2) -> Integer.compare(o1.sort, o2.sort)).collect(Collectors.toList())) 
     .collect(Collectors.toList()); 

но это возвращает Bar, в то время как я хочу список Foo

+4

Вы хотите, чтобы изменить существующие 'объекты Foo' (который не был бы очень функциональный ...) или создать новый' Foo' объекты с отсортированный список объектов «Бар»? –

+3

Вы должны сначала подумать о том, что вы на самом деле хотите сделать. Отсортируйте список, содержащийся в 'Foo.bars', или создайте новые экземпляры' Foo'. В первом случае просто вызовите 'List.sort' в этих списках. В последнем случае вам нужно построить новые экземпляры 'Foo' в вашей операции' map'. – Holger

+0

Я бы хотел новый список с отсортированными foos и отсортированными барами –

ответ

1
List<Foo> foosSort = foos.stream() 
        .sorted((o1, o2) -> (o1.sort - o2.sort)) 
        .map(f -> { 
          List<Bar> bars = f.bars.stream() 
          .sorted((o1, o2) -> (o1.sort- o2.sort)) 
          .collect(Collectors.toList()); 
          f.bars = bars; 
          return f; 
        }) 
        .collect(Collectors.toList()); 
+0

Я не думаю, что это работает. –

+0

Он должен работать тест один раз – Nagarjuna

+0

Я подтверждаю, что это тоже сработало! –

4

Следующие сортируют foos и bars за каждые foo, но так как peek операция мутирует f, это приведет к неожиданному поведению, если задействован параллелизм.

List<Foo> foosSorted = foos.stream() 
      .sorted(Comparator.comparingInt(o -> o.sort)) 
      .peek(f -> { 
       f.bars = f.bars.stream().sorted(Comparator.comparingInt(o -> o.sort)).collect(Collectors.toList()); 
      }) 
      .collect(Collectors.toList()); 

Что я предлагаю вам добавить конструктор Foo с sort и bars и использовать map вместо peek. Таким образом, мы не мутируем никакого объекта Foo, так что это можно запускать параллельно без проблем.

List<Foo> foosSorted = foos.stream() 
      .sorted(Comparator.comparingInt(o -> o.sort)) 
      .map(f -> { 
       return new Foo(f.sort, f.bars.stream().sorted(Comparator.comparingInt(o -> o.sort)).collect(Collectors.toList())); 
      }) 
      .collect(Collectors.toList()); 

с:

class Foo { 
    public int sort; 
    public List<Bar> bars; 
    public Foo(int sort) { 
     this.sort = sort; 
    } 
    public Foo(int sort, List<Bar> bars) { 
     this.sort = sort; 
     this.bars = new ArrayList<>(bars); 
    } 
} 
+0

Ok thanks. У меня это было почти. Мне просто нужно было создать новый foo в моей операции с картой. Благодаря! –

+1

Вам не нужны фигурные скобки, не в '.peek (f -> {f.bars = expression;})', которые можно просто написать как .peek (f -> f.bars = expression) ' , или в '.map (f -> {return expression;})', который может быть просто записан как '.map (f -> выражение)' ... – Holger

Смежные вопросы