How to split an HashMap in Java

41,266

Solution 1

Do you have to use HashMap?

TreeMap is really good for this kind of things. Here's an example (note that 0, 50, and 99 are map keys, not indices):

TreeMap<Integer, Integer> sorted = new TreeMap<Integer, Integer>(bigMap);

SortedMap<Integer, Integer> zeroToFortyNine = sorted.subMap(0, 50); // toKey inclusive, fromKey exclusive
SortedMap<Integer, Integer> fiftyToNinetyNine = sorted.subMap(50, true, 99, true);

Solution 2

You'll basically need to iterate over the entries in bigMap, and make a decision as to whether they should be added to smallMap1 or smallMap2.

Solution 3

As the HashMap is unordered (entries may come in any order), it makes no sense to exactly split it. We can simply use the alternating boolean flag.

boolean b = false;
for (Map.Entry e: bigMap.entrySet()) {
  if (b)
    smallMap1.put(e.getKey(), e.getValue());
  else
    smallMap2.put(e.getKey(), e.getValue());
  b = !b;
}

Solution 4

Here are two simple methods to split the map by,

  1. size of the partition or

  2. number of partitions

     /**
      *
      * @param bulkyMap - your source map to be partitioned
      * @param batchSize - partition size
      * @return
      */
     public List<Map<String, Object>> getMiniMapsInFixedSizeBatches(Map<String, Object> bulkyMap, int batchSize) {
         if (batchSize >= bulkyMap.size() || batchSize <= 0) {
             return Arrays.asList(bulkyMap);
         }
         List<Map<String, Object>> batches = new ArrayList<>();
         int innerBatchcount = 1;
         int count = 1;
         Map<String, Object> tempMap = new HashMap<>();
         for (Map.Entry<String, Object> entry : bulkyMap.entrySet()) {
             tempMap.put(entry.getKey(), entry.getValue());
             innerBatchcount++;
             count++;
             if (innerBatchcount > batchSize || count > bulkyMap.size()) {
                 innerBatchcount = 1;
                 Map<String, Object> batchedMap = new HashMap<>();
                 batchedMap.putAll(tempMap);
                 batches.add(batchedMap);
                 tempMap.clear();
             }
         }
         return batches;
     }
    
     /**
      * the number of partitions is not always guaranteed as the algorithm tries to optimize the number of partitions
      * @param bulkyMap - your source map to be partitioned
      * @param numPartitions  - number of partitions (not guaranteed)
      * @return
      */
     public List<Map<String, Object>> getMiniPartitionedMaps(Map<String, Object> bulkyMap, int numPartitions) {
         int size = bulkyMap.size();
         int batchSize = Double.valueOf(Math.ceil(size * 1.0 / numPartitions)).intValue();
         return getMiniMapsInFixedSizeBatches(bulkyMap, batchSize);
     }
    

Solution 5

Iterate over the bigMap with for (Entry<Integer, Integer> entry : bigMap.entrySet()), and increment an i to check whether you have to add the entry in the first small map or in the second one.

Share:
41,266
RNO
Author by

RNO

Updated on July 23, 2022

Comments

  • RNO
    RNO almost 2 years

    I was wondering if it is possible to split a HashMap into smaller sub-maps.

    In my case I have a HashMap of 100 elements and I would like to create 2 (or more) smaller HashMaps from the original one, the first containing the Entries from 0 to 49, the second containing the Entries from 50 to 99.

    Map <Integer, Integer> bigMap = new HashMap <Integer, Integer>();
    
    //should contains entries from 0 to 49 of 'bigMap'
    Map <Integer, Integer> smallMap1 = new HashMap <Integer, Integer>(); 
    
    
    //should contains entries from 50 to 99 of 'bigMap'
    Map <Integer, Integer> smallMap2 = new HashMap <Integer, Integer>();
    

    Any suggestions? Many thanks!

  • amphibient
    amphibient over 11 years
    or set a threshold and iterate to it, moving an entry from big to small each iteration
  • Oliver Charlesworth
    Oliver Charlesworth over 11 years
    @foampile: A threshold? What do you mean? (Remember that a hash-map isn't sorted)
  • amphibient
    amphibient over 11 years
    iterate up to a certain number of iterations, e.g. 50% rounded up to the next int of the original size. but even if it is not sorted, he is moving entries, i.e. putting them in new, deleting from old, so it is safe. so when he iterates again, the moved entries won't be there in the old
  • sharakan
    sharakan over 11 years
    huh? on a HashMap wouldn't this just arbitrarily pick every other entry?
  • Oliver Charlesworth
    Oliver Charlesworth over 11 years
    @foampile: Oh, I see. I had misread the OP's question. I assumed that (s)he wanted to filter the entries based on their values. But it sounds like they actually just want 50% to go one way, and 50% the other.
  • Audrius Meškauskas
    Audrius Meškauskas over 11 years
    There is no such thing as the order of entries in HashMap. If the order is important for your task, use LinkedHashMap and then of course it must be a different algorithm.
  • RNO
    RNO over 11 years
    I don't know why you received some downvote, I have chosen your answer because it does not waste much memory. The TreeMap enabled me to efficiently achieve what I wanted. P.S. I should have specified that the result should have been performing, and your suggestion it was. Thanks again
  • Shane
    Shane over 10 years
    In this answer's current state items 49 and 99 will not be included in either map, because the toKey argument of SortedMap's subMap method is exclusive. Why they didn't include an inclusive version I have no idea.
  • Shane
    Shane over 10 years
    What you probably want is Java 6's NavigableMap, which includes subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive);
  • sharakan
    sharakan over 10 years
    @Shane Thanks for the pointer, fixed the indexing. Note that TreeMap is a NavigableMap, so that method exists on TreeMap as well.
  • Olivier Faucheux
    Olivier Faucheux over 9 years
    This answer will only work with a map having as keys the numbers from 0 to 99. The parameters of method subMap(a,b) does not refers to the number of elements but to the values of the keys.If your maps contains the 100 numbers from 500 to 599, subMap(0,49) will be empty, as well als subMap(50,99). The only full map would be subMap(100, 99999999).
  • sharakan
    sharakan over 9 years
    @OlivierFaucheux That's correct, I made a simplifying assumption given that the OP didn't specify the actual values of the keys. The specific constants I selected also wouldn't work with negative ranges, wouldn't simply translate to non-contiguous ranges etc. Safe to say I didn't solve every problem, but I did provide an answer to his problem.
  • Fabrice TIERCELIN
    Fabrice TIERCELIN about 8 years
    This answer is confusing: it does not take the indices of entries into account but directly the keys. It can't be called a solution to split a map.
  • vkrishna17
    vkrishna17 over 7 years
    What if I don't consider ordering, its just that i want to split Map into smaller maps. How can I do it ?