2013-06-26 11 views
5

Mam więc następującą mapę HashMap:Tworzenie podzbioru HashMap na podstawie niektórych specyfikacji?

HashMap<String, List<someDataType>> map;

Chcę utworzyć nową mapę HashMap, która składa się tylko z par k/v z map, które mają wartość (listę), której długość jest mniejsza niż pewne "x". Jedyny sposób, w jaki wiem, jak to zrobić, polega na iteracji przez HashMap i umieszczeniu par K/V w nowej HashMap. Czy istnieje bardziej zwięzły sposób na osiągnięcie tego, czego szukam? Dzięki.

+0

Nie to, co wiem. – jlordo

+1

Będziesz musiał zachować dodatkowe ograniczenia na mapie, aby nie wykonywać iteracji po całej mapie. Jeśli na przykład Twoja mapa została posortowana rosnąco według długości list, to możesz pętać, aż zobaczysz długość 1 poza x. –

+0

@HunterMcMillen: Czy znasz mapę sortowaną na podstawie wartości? – jlordo

Odpowiedz

8

Korzystanie guawa:

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

gdzie:

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 Zadzwoń do mnie - ale zauważ, że 'filterEntries' po prostu odeśle przefiltrowany * widok * mapy bazowej, na wypadek gdyby OP chciał ją skopiować. Również "filterValues" będzie bardziej zwięzły. –

+0

Przyznanie używania Guawy, czy "ArrayListMultiMap" i "MultiMaps.filterkeys" nie byłyby lepszym rozwiązaniem? 'MultpMaps.filterValues' lub' .filterEntries' nie działają, ponieważ otrzymujesz każdą indywidualną wartość lub parę klucz-wartość. –

0

Alternatywnie można wykonać kopię oryginalnej mapy i powtórzyć wartości, usuwając te, których długość jest mniejsza niż x.

4

Jeśli biblioteka Guava jest dostępny do projektu, można użyć Maps.filterValues (nieco echem odpowiedź Keitha):

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); 

Uwaga na potrzebę kopii, ponieważ filterValues zwraca przefiltrowany widok oryginalnej mapy.

Aktualizacja: z Java 8 można uprościć predykat do wyrażenia lambda:

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

Możesz zajrzeć na Guava biblioteki Google. Istnieje ogromna liczba powiązanych z nim narzędzi, takich jak Collections i Map, które pozwalają ci dość lapidarnie wykonywać skomplikowane operacje. Przykładem tego, co można zrobić, to:

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); 

Jestem pewien, że można znaleźć coś w tam, co może zrobić to, czego szukasz :-)

+0

Kiedy zacząłem pisać, nie było odpowiedzi ... kiedy składałem, były 2 odpowiedzi od ludzi, którzy znają Guava lepiej ode mnie! : -O – Stewart

0

będzie wraz z innymi przykładami guawy, można użyć guawy za 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; 
     } 
}); 

Sposób MultiMaps.newListMultiMap bierze argumenty nie chcesz, aby zapewnić. Nie można tutaj użyć MultiMaps.filterValues ani .filterEntries, ponieważ używają one indywidualnych wartości, a nie list wartości. Z drugiej strony, mmap.get(k) nigdy nie zwraca null. Oczywiście, jeśli korzystasz z kamery, użyj statycznej klasy wewnętrznej, którą przechodzą mmap i limit zamiast używać anonimowych klas wewnętrznych.

Powiązane problemy