列表在map <key,values>中作为值给出,如何找到列表大小最大的一个或多个键java

时间:2018-11-28 15:25:46

标签: java performance dictionary iteration

我写了一个返回地图的方法。 地图的结构是:

Process: com.example.app, PID: 14212
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.SCAN_RESULTS flg=0x4000010 } in com..app.MainActivity$WifiScanReceiver@424b88a0
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:773)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:146)
    at android.app.ActivityThread.main(ActivityThread.java:5756)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
    at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.StringIndexOutOfBoundsException: length=0; index=5
    at java.lang.String.indexAndLength(String.java:584)
    at java.lang.String.substring(String.java:1449)
    at com.example.app.MainActivity$WifiScanReceiver.onReceive(MainActivity.java:83)
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:763)
    at android.os.Handler.handleCallback(Handler.java:733) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:146) 
    at android.app.ActivityThread.main(ActivityThread.java:5756) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:515) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) 
    at dalvik.system.NativeStart.main(Native Method) 

该地图可以包含1000个以上的键,每个键可以包含大小超过10000个的列表。 我想获得那些具有最大列表大小的键。如果可能的话,有什么方法可以在最短的时间内得到结果?

5 个答案:

答案 0 :(得分:3)

使用流,您可以组合一个解决方案,该解决方案可迭代地图的所有条目,获取每个列表的 size ,以最终提供具有“ max”大小列表的键。或者,您可以按照尼古拉斯(Nikolas)的回答中的建议,实施这种“守旧派”方法。

问题在于:如果您需要经常执行此操作,则仍然可能会导致性能问题。从这种角度来看,您应该问自己:数据的这种“布局”是否真的是您的需要。

含义:您可以使用TreeMap并给它一个特殊的比较器,而不是使用Map。然后,这些地图会根据这些列表的长度对其进行排序。然后,您只需选择“第一个”条目,就可以赢得赢家。这里的缺点是比较器仅对进入映射的键起作用,因此您可能需要一些特殊的“包装类”,其中键知道列表的大小。真丑。

或者,您可以创建一个特殊的“包装图”,内部包含两个图:

  • 将列表大小映射到“真实”映射键的TreeMap<Integer, String>
  • 保存您的实际数据的真实Map<String, List<String>>

答案 1 :(得分:2)

如果将性能放在首位,请忘记并通过简单的for-loop迭代使用本机方法。

String maxKey;
int maxSize = -1;

for (Entry<String, List<String>> list: map.entrySet()) {
    int size = list.getValue().size();
    if (size  > maxSize) {
        maxKey = list.getKey();
        maxSize = size;
    }
}

如果要存储最大数量的所有密钥,请将它们存储到Set<String>并将条件替换为:

int size = list.getValue().size();
if (size  == maxSize) {
    maxKeySet.add(list.getKey());
}
if (size  > maxSize) {
    maxKeySet.clear();
    maxKeySet.add(list.getKey());
    maxSize = size;
}

答案 2 :(得分:0)

使用java8流过滤器功能:

Map <String, List<String>> map = new HashMap<>();

Map <String, List<String>> filteredMap = map.entrySet().stream()
                    .filter(stringListEntry -> stringListEntry.getValue().size() > 100)
                    .limit(10)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

`

答案 3 :(得分:0)

按值列表的大小对条目进行分组,采用有助于您找到最大键的数据结构:

TreeMap<Integer, List<Entry<String, List<String>>>> collect =
    map.entrySet().stream()
        .collect(groupingBy(e -> e.getValue().size(), TreeMap::new, toList()));

(您可以使用mapping(Map.Entry::getKey, toList())而不是toList()来获取密钥)。

然后使用以下命令获取最大尺寸的条目:

List<Map.Entry<String, List<String>>> largestEntries =
    grouped.lastEntry().getValue();

当然,您也可以在没有流的情况下执行此操作,并且无需保留所有小于最大条目的条目:

List<Map.Entry<String, List<String>>> largestEntries = new ArrayList<>();
// Don't need both this and largestEntries;
// just adding to show how you'd only get keys.
List<String> largestKeys = new ArrayList<>();  
int largestSize = Integer.MIN_VALUE;

for (Map.Entry<String, List<String>> entry : map.entrySet()) {
  if (entry.getValue().size() > largestSize) {
    largestEntries.clear();
    largestEntries.add(entry);
    largestKeys.add(entry.getKey());
    largestSize = entry.getValue().size();
  } else if (entry.getValue().size() == largestSize) {
    largestEntries.add(entry);
    largestKeys.add(entry.getKey());
  }
}

答案 4 :(得分:0)

您仍然可以使用java-steam API:

  Map<String, List<Integer>> map = Map.of(
                                        "a",List.of(1,2),
                                        "b",List.of(3,4,5,6),
                                        "c",List.of(7,8,9)
                                   );

具有最大列表大小的条目:

Optional<Map.Entry<String, List<Integer>>> max = map.entrySet()
                    .stream()
                    .max(Comparator.comparingInt(value -> value.getValue().size()));

具有最大列表大小的条目的地图:

Integer maxSize = max.get().getValue().size();
Map<String, List<Integer>> maxMap = map
        .entrySet()
        .stream()
        .filter(entry -> entry.getValue().size() == maxSize)
        .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));

或者最后,您可以对Map进行排序并将结果存储在LinkedHashMap中:

LinkedHashMap<String, List<Integer>> sortedMap = map
        .entrySet()
        .stream()
        .sorted(Comparator.comparingInt(value -> value.getValue().size()))
        .collect(
                Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (u, v) -> {
                            throw new IllegalStateException(String.format("Duplicate key %s", u));
                        }, 
                        LinkedHashMap::new 
                )
        );