2017-06-05 55 views
2

的GROUPBY結果我有水果的清單包含姓名和身​​份證應用操作上流

List<Fruit> fruitList = Arrays.asList(new Fruit("apple", 1), new Fruit("orange", 2), new Fruit("orange", 3)); 

我想和名_ID重命名的水果名稱只有重複的水果名稱存在就像在我的名單橙色的情況下,將重命名爲orange_2和orange_3,但蘋果將保持蘋果。 如何以單流表達方式做到這一點。

,我想出瞭解決的辦法是

Map<String, List<Fruit>> fruitMap = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName)); 

     Set<Entry<String, List<Fruit>>> entry = fruitMap.entrySet(); 

     for (Entry<String, List<Fruit>> en : entry) { 
      List<Fruit> fruit = en.getValue(); 
      if (fruit.size() > 1) { 
       fruit.stream().map(d -> { 
        d.setName(d.getName() + "_" + d.getId()); 
        return d; 
       }).collect(Collectors.toList()); 
      } 
     }  
    } 

但這是遠遠不止一個流表達。

回答

2

我不認爲你可以逃脫幾次沒有流。這裏是一個小的解決方案及略微更可讀,我認爲:

Set<String> repeated = fruits.stream() 
      .collect(Collectors.groupingBy(Fruit::getName, Collectors.counting())) 
      .entrySet() 
      .stream() 
      .filter(e -> e.getValue() > 1) 
      .map(Entry::getKey) 
      .collect(Collectors.toSet()); 

    fruits.forEach(f -> { 
     if (repeated.contains(f.getName())) { 
      f.setName(f.getName() + "_" + f.getId()); 
     } 
    }); 

    System.out.println(fruits); // [name = apple id = 1, name = orange_2 id = 2, name = orange_3 id = 3] 
+0

謝謝,但是,這仍然是2個表達式,這不是我所看到的。 –

0

下面是我想出的代碼,但它仍然是2表達

Map<String, Long> fruitMap = fruitList.stream() 
       .collect(Collectors.groupingBy(Fruit::getName, Collectors.counting())); 

     fruitList.forEach(f -> { 
      if (fruitMap.get(f.getName()) > 1) { 
       f.setName(f.getName() + "_" + f.getId()); 
      } 
     }); 
3

下面是一個(在某種程度上)單眼線:

fruitList.stream().collect(Collectors.groupingBy(Fruit::getName)) 
    .values().stream() 
     .filter(list -> list.size() > 1) 
     .forEach(list -> list.forEach(Fruit::renameWithId)); 

這裏假設你有在Fruit下面的方法:

public void renameWithId() { 
    name = name + "_" + id; 
} 

如果您不能修改Fruit類,你可以做重命名內聯:

fruitList.stream().collect(Collectors.groupingBy(Fruit::getName)) 
    .values().stream() 
     .filter(list -> list.size() > 1) 
     .forEach(list -> list.forEach(fruit -> 
      fruit.setName(fruit.getName() + "_" + fruit.getId()))); 

這些長的單行是這麼久,他們不再是單行,儘管他們的名字...此外,代碼最終難以閱讀,並且很難維護和測試。因此,我建議您移動穿越地圖和重命名的成果爲新方法的代碼:

private void renameRepeatedFruits(Map<String, List<Fruit>> fruitMap) { 
    fruitMap.values().stream() 
     .filter(list -> list.size() > 1) 
     .forEach(list -> list.forEach(Fruit::renameWithId)); 
} 

這將讓你大大簡化代碼的第一個版本:

renameRepeatedFruits(
    fruitList.stream().collect(Collectors.groupingBy(Fruit::getName))); 
+2

...但將第二個操作鏈接到第一個操作時將更簡潔,而不是使用收集器進行操作。 'fruitList.stream()。collect( Collectors.groupingBy(Fruit :: getName)).values()。stream().filter(list - > list.size()> 1).forEach(list - > list。的forEach(水果:: renameWithId));' – Holger