2015-08-31 31 views
6

我有一個類A的列表,其中包括一個列表本身。如何使用Java 8 Stream擴展並重新組合列表列表?

public class A { 
    public double val; 
    public String id; 
    public List<String> names = new ArrayList<String>(); 
    public A(double v, String ID, String name) 
    { 
     val = v; 
     id = ID; 
     names.add(name); 
    } 

static public List<A> createAnExample() 
{ 
    List<A> items = new ArrayList<A>(); 

    items.add(new A(8.0,"x1","y11")); 
    items.add(new A(12.0, "x2", "y21")); 
    items.add(new A(24.0,"x3","y31")); 
    items.get(0).names.add("y12"); 
    items.get(1).names.add("y11"); 
    items.get(1).names.add("y31"); 
    items.get(2).names.add("y11"); 
    items.get(2).names.add("y32"); 
    items.get(2).names.add("y33"); 
    return items; 
} 

目標是對列表中每個id的平均值進行求和。我通過使用一些Java 8流在Main函數中添加了代碼。 我的問題是我怎樣才能以更優雅的方式重寫它,而不使用第二個數組和for循環。

static public void main(String[] args) { 
    List<A> items = createAnExample(); 

    List<A> items2 = new ArrayList<A>(); 
    for (int i = 0; i < items.size(); i++) { 
     List<String> names = items.get(i).names; 
     double v = items.get(i).val/names.size(); 
     String itemid = items.get(i).id; 
     for (String n : names) { 
      A item = new A(v, itemid, n); 
      items2.add(item); 
     } 
    } 
    Map<String, Double> x = items2.stream().collect(Collectors.groupingBy(item -> 
      item.names.isEmpty() ? "NULL" : item.names.get(0), Collectors.summingDouble(item -> item.val))); 
    for (Map.Entry entry : x.entrySet()) 
     System.out.println(entry.getKey() + " --> " + entry.getValue()); 
} 

回答

4

你可以用flatMap做到這一點:

x = items.stream() 
    .flatMap(a -> a.names.stream() 
     .map(n -> new AbstractMap.SimpleEntry<>(n, a.val/a.names.size())) 
    ).collect(groupingBy(
     Map.Entry::getKey, summingDouble(Map.Entry::getValue) 
    )); 

如果你發現自己處理這類問題的時候,考慮其靜態方法來創建一個Map.Entry

static<K,V> Map.Entry<K,V> entry(K k, V v) { 
    return new AbstractMap.SimpleImmutableEntry<>(k,v); 
} 

然後你將具有較少的冗長.map(n -> entry(n, a.val/a.names.size()))

1

在m y免費StreamEx擴展標準Stream API的庫有一些特殊操作可幫助構建如此複雜的地圖。使用StreamEx你的問題可以解決這樣的:

Map<String, Double> x = StreamEx.of(createAnExample()) 
    .mapToEntry(item -> item.names, item -> item.val/item.names.size()) 
    .flatMapKeys(List::stream) 
    .grouping(Collectors.summingDouble(v -> v)); 

這裏mapToEntry創建映射條目(所謂EntryStream),其中鍵是名稱的列表和值的平均值丘壑流。接下來,我們使用flatMapKeys來平整保留值的鍵(因此我們有Entry<String, Double>)。最後,我們將它們分組在一起總結重複鍵的值。