2015-04-04 40 views
2

我是Java新手8 lambda表達式如何檢索根據標記爲「否」的標籤排序的收藏標籤列表?

我有一個List<Post>其中每個Post可以屬於多個帖子。

class Post{ 
    String name; 
    List<String> tags; 
    .... 
} 

我希望檢索基於無後通過其標籤排序最喜歡的標籤列表。如何使用lambda表達式來實現它?以JSON形式存儲在MongoDB中

樣品輸入:

[ 
    { 
     "name": "java with spring", 
     "tags": [ 
      "java", 
      "spring" 
     ] 
    }, 
    { 
     "name": "spring with mongodb", 
     "tags": [ 
      "java", 
      "spring", 
      "mongodb" 
     ] 
    }, 
    { 
     "name": "spring with hibernate", 
     "tags": [ 
      "java", 
      "spring", 
      "hibernate" 
     ] 
    } 
] 

預期輸出:

java,spring,mongodb,hibernate 

以下是我在下面的答案後試圖:;

List<Post> posts = ... 

List<String> tags = new ArrayList<>(); 
Map<String, Integer> map = new TreeMap<String, Integer>(); 

// get list of all tags 
posts.stream().forEach(post -> tags.addAll(post.getTags())); 
// populate map with tag and its count (frequency) 
tags.stream().forEach(tag -> map.put(tag, map.get(tag) == null ? 1 : map.get(tag) + 1)); 

Comparator<Entry<String, Integer>> byValue = (entry1, entry2) -> entry1.getValue().compareTo(entry2.getValue()); 
// sort the map by value and return the sorted keys as favorite tags 
List<String> favoriteTags = map.entrySet().stream().sorted(byValue.reversed()).map(e -> e.getKey()).collect(Collectors.toList()) 

回答

2

我不知道是否有可能在一個單一的表達來實現這一點,但它是可以做到這兩個步驟,首先通過構建圖,可計算每個標籤的出現次數的數量:

Map<String, Integer> tags = new HashMap<>(); 
posts.forEach(p -> p.tags.forEach(t -> tags.put(t, tags.get(t) != null ? tags.get(t)+1 : 1))); 
List<String> sortedTags = tags.entrySet().stream().sorted((e1, e2) -> e2.getValue() - e1.getValue()).map(e -> e.getKey()).collect(Collectors.toList()); 
+0

是的,它是我上次編輯的簡化版本。謝謝 – Braj 2015-04-04 19:19:32

+0

沒問題,但我對Java 8 lambda表達式也很陌生,我想知道是否有辦法在單個表達式中實現這一點。我很確定有一種方法... – Neumann 2015-04-04 19:20:29

0

我不會使用lambda表達式,因爲它們不能真正幫助。

我會以其他方式使用GuavaMultiset,然後按次數排序。

List<Post> posts = ... ; 
Multiset<String> tags = HashMultiset.create(); 
posts.stream().forEach((p) -> tags.addAll(p.getTags())); 
// Now we have the frequency. Let's sort it. 
tags = Multisets.copyHighestCountFirst(tags); 
// You want only the tags and nothing else? No problem 
Set<String> strings = tags.elementSet(); 

Lambdas不能解決所有問題。只需使用正確的工具進行正確的任務即可。

+0

感謝您的幫助。我正在尋找Java本身的解決方案,但這是一個很好的答案。 – Braj 2015-04-04 18:30:04

1

你可以用下面的辦法:

static class Helper { 
    String name; 
    String tag; 

    Helper(final String name, final String tag) { 
     this.name = name; 
     this.tag = tag; 
    } 

} 

static void getFavourites() { 
    final List<String> favourites = 
      new ArrayList<Post>().stream().<Helper> flatMap(p -> p.tags.stream().map(t -> new Helper(p.name, t))) 
        .collect(groupingBy(h -> h.tag, Collectors.summingInt(x -> 1))).entrySet().stream() 
        .sorted(Comparator.comparingInt(e -> e.getValue())) 
        .map(e -> e.getKey()) 
        .collect(toList()); 
} 

(投僅存在因爲Eclipse抱怨)。 這個想法是顛倒帖子和標籤之間的映射(也可以使用multimap完成),計算標籤的出現並對它們進行排序。

當然,您必須將new ArrayList<Post>()替換爲您的實際數據。

+0

很長的表情。讓我試着去理解它。我不想複雜它。 – Braj 2015-04-04 18:32:18