9

我想知道是否可以将 HashMap 拆分为更小的子图。

在我的例子中,我有一个 100 个元素的 HashMap,我想从原始元素创建 2 个(或更多)更小的 HashMap,第一个包含从 0 到 49 的条目,第二个包含从 50 到 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>();

有什么建议么?非常感谢!

4

11 回答 11

17

你必须使用HashMap吗?

TreeMap真的很适合这种事情。这是一个示例(请注意,0、50 和 99 是映射键,而不是索引):

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);
于 2013-01-31T15:45:26.713 回答
3

您基本上需要遍历 中的条目bigMap,并决定是否应将它们添加到smallMap1smallMap2中。

于 2013-01-31T15:42:07.620 回答
3

由于HashMap是无序的(条目可能以任何顺序出现),因此完全拆分它是没有意义的。我们可以简单地使用交替的布尔标志。

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;
}
于 2013-01-31T15:44:52.253 回答
1

遍历bigMapwithfor (Entry<Integer, Integer> entry : bigMap.entrySet())并增加 ani以检查您是否必须在第一个小地图或第二个小地图中添加条目。

于 2013-01-31T15:45:21.193 回答
1

这是一个使用 SortedMap 的解决方案:

public static <K, V> List<SortedMap<K, V>> splitMap(final SortedMap<K, V> map, final int size) {
    List<K> keys = new ArrayList<>(map.keySet());
    List<SortedMap<K, V>> parts = new ArrayList<>();
    final int listSize = map.size();
    for (int i = 0; i < listSize; i += size) {
        if (i + size < listSize) {
            parts.add(map.subMap(keys.get(i), keys.get(i + size)));
        } else {
            parts.add(map.tailMap(keys.get(i)));
        }
    }
    return parts;
}
于 2016-06-03T12:54:49.673 回答
1

这里有两种简单的方法来分割地图,

  1. 分区的大小或

  2. 分区数

     /**
      *
      * @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);
     }
    
于 2020-03-04T14:03:40.470 回答
1

您可以使用 Guava Iterables 分区方法和 Java 流接口来解决它。

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public static <K, V> List<Map<K, V>> split(Map<K, V> map, int size) {
    List<List<Map.Entry<K, V>>> list = Lists.newArrayList(Iterables.partition(map.entrySet(), size));

    return list.stream()
            .map(entries ->
                    entries.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
            )
            .collect(Collectors.toList());
}    
于 2020-04-10T06:15:21.907 回答
0
for (Map.Entry<Integer,Integer> entry : bigMap.entrySet()) {
   // ...
}

是迭代原始地图的最快方法。然后,您将使用Map.Entry键来决定要填充哪个新地图。

于 2013-01-31T15:44:09.377 回答
0

这是对我有用的功能之一,我希望它对其他人有帮助。无论存储为键的对象/原语如何,这个都可以工作。

上面建议的 TreeMap 方法只有在键是原始的、有序的和精确的索引序列时才有效。

    public List<Map<Integer, EnrichmentRecord>> splitMap(Map<Integer, EnrichmentRecord> enrichmentFieldsMap,
            int splitSize) {

        float mapSize = enrichmentFieldsMap.size();
        float splitFactorF = splitSize; 
        float actualNoOfBatches = (mapSize / splitFactorF);
        double noOfBatches = Math.ceil(actualNoOfBatches);



        List<Map<Integer, EnrichmentRecord>> listOfMaps = new ArrayList<>();

        List<List<Integer>> listOfListOfKeys = new ArrayList<>();


        int startIndex = 0;
        int endIndex = splitSize;

        Set<Integer> keys = enrichmentFieldsMap.keySet();
        List<Integer> keysAsList = new ArrayList<>();
        keysAsList.addAll(keys);

        /*
         * Split the keys as a list of keys,  
         * For each key sub list add to a Primary List - listOfListOfKeys
         */
        for (int i = 0; i < noOfBatches; i++) {
            listOfListOfKeys.add(keysAsList.subList(startIndex, endIndex));         
            startIndex = endIndex;
            endIndex = (int) (((endIndex + splitSize) > mapSize) ? mapSize : (endIndex + splitSize));
        }

         /**
         * For Each list of keys, prepare a map
         *
         **/
        for(List<Integer> keyList: listOfListOfKeys){
            Map<Integer,EnrichmentRecord> subMap = new HashMap<>();
            for(Integer key: keyList){
                subMap.put(key,enrichmentFieldsMap.get(key));
            }
            listOfMaps.add(subMap);
        }

        return listOfMaps;
    }
于 2017-01-19T21:20:04.210 回答
0

这可能是使用 headMap 和 tailMap 的另一种解决方案

SortedMap<Integer, String> map1 = new TreeMap<>();
    map1.put(2, "Abc");
    map1.put(3, "def");
    map1.put(1, "xyz");
    map1.put(5, "mddf");
    System.out.println(map1);

    SortedMap<Integer, String> sm1 = map1.headMap(4); // from 0 to x (key) from front
    SortedMap<Integer, String> sm2 = map1.tailMap(1); //tail starting from key
    System.out.println("Head Map"+ sm1);
    System.out.println("Tail Map"+sm2);

输出是

{1=xyz, 2=Abc, 3=def, 5=mddf}
Head Map{1=xyz, 2=Abc, 3=def}
Tail Map{1=xyz, 2=Abc, 3=def, 5=mddf}
于 2020-03-27T11:35:17.150 回答
0

从@Nizamudeen Karimudeen 的回答构建,如果没有大量的重写,我就无法开始工作......这个方法适用于其中包含任何类的任何 HashMap。

因此,假设您要拆分的 Map 定义如下:

Map<String, MyClass> myMap = new HashMap<>();

如果您希望将其拆分为 20 个单独的地图,您只需将其拆分为:

List<Map<String, MyClass>> splitMapList = splitMap(myMap, 20);

然后要使用每个单独的地图,您可以像这样遍历它们:

for (Map<String, MyClass> mySplitMap : splitMapList) {
     for(String key : mySplitMap.keySet()) {
         MyClass myClass = mySplitMap.get(key);
     }
}

或者您可以通过列表的索引等直接引用它们。

Map<String, MyClass> subMap = splitMapList.get(3);

这是方法:

public static List<Map<KeyClass, ValueClass>> splitMap(Map<KeyClass, ValueClass> originalMap, int splitSize) {
    int mapSize = originalMap.size();
    int elementsPerNewMap = mapSize / splitSize;
    List<Map<KeyClass, ValueClass>> newListOfMaps = new ArrayList<>(); //Will be returned at the end after it's built in the final loop.
    List<List<KeyClass>> listOfMapKeysForIndexing = new ArrayList<>(); //Used as a reference in the final loop.
    List<KeyClass> listOfAllKeys = new ArrayList<>(originalMap.keySet());
    int maxIndex = listOfAllKeys.size() - 1; //We use this in the first loop to make sure that we never exceed this index number or we will get an index out of range.
    int startIndex = 0;
    int endIndex = elementsPerNewMap;
    for (int i = 0; i < splitSize; i++) { //Each loop creates a new list of keys which will be the entire set for a new subset of maps (total number set by splitSize.
        listOfMapKeysForIndexing.add(listOfAllKeys.subList(startIndex, endIndex));
        startIndex = Math.min((endIndex + 1), maxIndex);//Start at the next index, but don't ever go past the maxIndex or we get an IndexOutOfRange Exception
        endIndex = Math.min((endIndex + elementsPerNewMap), maxIndex);//Same thing for the end index.
    }
    /*
     * This is where we use the listOfMapKeysForIndexing to create each new Map that we add to the final list.
     */
    for(List<KeyClass> keyList: listOfMapKeysForIndexing){
        Map<KeyClass,ValueClass> subMap = new HashMap<>(); //This should create a quantity of these equal to the splitSize.
        for(KeyClass key: keyList){
            subMap.put(key,originalMap.get(key));
        }
        newListOfMaps.add(subMap);
    }
    return newListOfMaps;
}
于 2021-04-18T20:41:49.873 回答