2017-10-12 90 views
3

我有一個類說Level(它只是一個理解的虛擬類)。 我想根據levelId排序TreeMap<Level,Set<String>>。 請從下面的代碼如何使用流從列表中排序TreeMap

import java.util.*; 
import java.util.stream.Collectors; 

    public class Level { 
     int levelId; 

     public Level(int levelId) { 
      this.levelId = levelId; 
     } 

     public static Level getLevel(String name){ 
      return new Level(name.length()); 
     } 

     public static void main(String[]args){ 
      Set<String> names=new HashSet<>(); 
      names.add("Mahesh"); 
      names.add("Ram"); 
      names.add("Rita"); 

      Map<Level, Set<String>> map = names.stream().collect(
        Collectors.groupingBy(name->Level.getLevel(name), 
        Collectors.mapping(name->name,Collectors.toSet()))); 

     } 
    } 

我也試圖與Collectors.collectingAndThen()

任何幫助表示讚賞。

在此先感謝。

+1

https://docs.oracle.com/javase/8/docs/api/java/util /stream/Collectors.html#groupingBy-java.util.function.Function-java.util.function.Supplier-java.util.stream.Collector- –

+0

使用for循環而不是流 –

+5

'Collectors.groupingBy(Level :: getLevel,TreeMap :: new,Collectors.toSet())' – 4castle

回答

3

如果你不想讓Level實現Comparable,你需要一個Comparator。然後,你必須通過lambda表達式使用該分離器作爲地圖工廠到groupingBy集電極創建TreeMap

public class Level { 
    int levelId; 

    public Level(int levelId) { 
     this.levelId = levelId; 
    } 

    public static Level getLevel(String name){ 
     return new Level(name.length()); 
    } 

    public int getLevelId() { 
     return levelId; 
    } 

    public static void main(String[]args){ 
     Set<String> names=new HashSet<>(); 
     names.add("Mahesh"); 
     names.add("Ram"); 
     names.add("Rita"); 

     Comparator<Level> c = Comparator.comparingInt(Level::getLevelId); 
     Map<Level, Set<String>> map = names.stream() 
      .collect(Collectors.groupingBy(
         Level::getLevel,() -> new TreeMap<>(c), Collectors.toSet())); 
    } 
} 
4

你的修改工作的代碼是這樣的,請參閱@ 4castle評論:

public class Level implements Comparable<Level> { 
    int levelId; 

    public Level(int levelId) { 
     this.levelId = levelId; 
    } 

    @Override 
    public int compareTo(Level o) { 
     return Integer.compare(levelId, o.levelId); 
    } 

    public static Level getLevel(String name){ 
     return new Level(name.length()); 
    } 

    public static void main(String[]args){ 
     Set<String> names=new HashSet<>(); 
     names.add("Mahesh"); 
     names.add("Ram"); 
     names.add("Rita"); 

     Map<Level, Set<String>> map = names.stream().collect(
       Collectors.groupingBy(Level::getLevel, TreeMap::new, 
         Collectors.toSet())); 
    } 
} 
+1

是的,只是修改了答案。 –

1

在我看來,使用流僅在最簡單的情況下,提高了可讀性。如果您有特定要求,例如您需要特定的Map實現,或者您需要使用自定義Comparator,我強烈建議使用for循環。是的,你可以在Collectors這個類中搜索合適的方法,但是我相信如果你以後需要做一些小的修改,那麼結果代碼就難以遵循,並且不夠靈活。

在Java 8中,Map接口有很多改進,這意味着在循環中執行這種事情現在比以前的情況要少得多。

Map<Level, Set<String>> result = new TreeMap<>(Comparator.comparingInt(level -> level.levelId)); 
for (String name : names) 
    result.computeIfAbsent(getLevel(name), k -> new HashSet<>()).add(name); 

在這種情況下,爲什麼你想與Level鍵地圖反正我不知道。既然你想通過id來分組,那麼對於密鑰是Integer s更合理嗎?

Map<Integer, Set<String>> result = new TreeMap<>(); 
for (String name : names) 
    result.computeIfAbsent(getLevel(name).levelId, k -> new HashSet<>()).add(name); 
+2

我想,問題的Level getLevel(String name)方法只是實際操作的佔位符。有[類似的現實生活類](https://docs.oracle.com/javase/8/docs/api/?java/util/logging/Level.html)。順便說一句,我不認爲[基於流的解決方案](https://stackoverflow.com/a/46704101/2711488)比循環替代方案的可讀性差。有些情況下,循環好得多,但我不會說這裏已經超過了閾值。 – Holger