2013-06-26 44 views
5

所以我有以下HashMap:根據某些規範創建HashMap的子集?

HashMap<String, List<someDataType>> map;

我想創建一個新的HashMap,它只包含map中的k/v對,其長度小於某個「x」的值(列表)。我知道如何做到這一點的唯一方法是遍歷HashMap並將k/v對放入新的HashMap中。有沒有一種更簡潔的方式來實現我在找的東西?謝謝。

+0

不是我所知道的。 – jlordo

+1

您將不得不在地圖上保留額外的約束,以便不必遍歷整個地圖。例如,如果您的地圖按列表長度升序排列,那麼您可以循環播放,直到看到長度爲1的x以外的地方。 –

+0

@HunterMcMillen:你知道一個基於值排序的地圖嗎? – jlordo

回答

8

使用番石榴:

Map<String, List<String>> newMap = 
    Maps.filterEntries(originalMap, new MyEntryPredicate(10)); 

其中:

private static class MyEntryPredicate implements Predicate<Map.Entry<String, List<String>>> { 

    // max list length, exclusive 
    private int maxLength; 

    private MyEntryPredicate(int maxLength) { 
     this.maxLength = maxLength; 
    } 

    @Override 
    public boolean apply(Map.Entry<String, List<String>> input) { 
     return input != null && input.getValue().size() < maxLength; 
    } 
} 
+0

+1擊敗我 - 但請注意,「filterEntries」只會返回基礎地圖的過濾*視圖*,以防OP想要複製它。 'filterValues'會更簡潔。 –

+0

承認使用番石榴,是不是'ArrayListMultiMap'和'MultiMaps.filterkeys'更適合? 'MultpMaps.filterValues'或'.filterEntries'不起作用,因爲你得到每個單獨的值或鍵值對。 –

0

或者,您可以製作原始貼圖的副本,然後遍歷這些值,以消除長度小於x的值。

4

如果Guava庫是提供給你的項目,你可以使用Maps.filterValues(有點呼應基思的答案):

final int x = 42; 

Map<String, List<String>> filteredMap = 
     Maps.filterValues(map, new Predicate<Collection<?>>() { 
      @Override 
      public boolean apply(final Collection<?> collection) { 
       return collection.size() < x; 
      } 
     }); 

Map<String, List<String>> filteredMapCopy = ImmutableMap.copyOf(filteredMap); 

請注意需要複印件,因爲filterValues返回原始地圖的過濾視圖

更新:與Java 8你能夠簡化謂詞lambda表達式:

Map<String, List<String>> filteredMap = Maps.filterValues(map, list -> list.size() < x); 
0

你可能想看看從谷歌Guava庫。其中有大量的CollectionsMap相關的應用程序,它可以讓你做相當簡潔的複雜工作。你可以做一個例子是:

Iterable<Long> list = 
    Iterables.limit(
     Iterables.filter(
      Ordering.natural() 
        .reverse() 
        .onResultOf(new Function<Long, Integer>() { 
         public Integer apply(Long id) { 
          return // result of this is for sorting purposes 
         } 
        }) 
        .sortedCopy(
         Multisets.intersection(set1, set2)), 
       new Predicate<Long>() { 
        public boolean apply(Long id) { 
         return // whether to filter this id 
        } 
       }), limit); 

我相信你能找到的東西在裏面,可以做你找什麼:-)

+0

當我開始寫這篇文章的時候,沒有答案......當我提交的時候,有兩個人認識番石榴比我更好! :-O – Stewart

0

與其他番石榴例子一起去,你可以用番石榴的MultiMap S:

final MultiMap<K, V> mmap = ArrayListMultiMap.create(); 
// do stuff. 
final int limit = 10; 
final MultiMap<K, V> mmapView = 
    MultiMaps.filterKeys(mmap, new Predicate<K>(){ 
     public boolean apply(K k) { 
      return mmap.get(k).size() <= limit; 
     } 
}); 

MultiMaps.newListMultiMap方法需要你不想提供的參數。您不能在這裏使用MultiMaps.filterValues.filterEntries,因爲這些使用的是單個值,而不是值的列表。另一方面,mmap.get(k)從不會返回null。當然,您可以使用通過mmaplimit而不是使用匿名內部類的靜態內部類。