使用半已知键在 ArrayLists 的 HashMap 中查找最大值和最小值 - Java
Finding the maximum and minimum values in a HashMap of ArrayLists with semi-known key - Java
我有一个 ArrayLists 的 HashMap 如下:
HashMap<String, ArrayList<Double>> Flkn = new HashMap<String, ArrayList<Double>>();
Flkn.put("T_"+l+"_"+k+"_"+n, new ArrayList());
l
、k
和 n
根据几个循环获取它们的值,因此它们的值会根据参数而变化。
在这种情况下,我想知道对于给定的 k 值,如何在相关的 ArrayList 中找到元素的最小值和最大值。 (请注意,长度或 ArrayLists 也取决于参数)
例如,假设我想知道 k=3
的 ArrayList 中的最小值和最大值。那么我正在寻找的是所有 l
和 n
的每个值都具有键 ("T_"+l+"_"+3+"_"+n)
的 ArrayList。这里的问题是我无法预测 l
和 n
的值,因为它们完全依赖于代码。另一个不方便的事情是我想从 l
和 n
获取它们的值的循环中获取最小值和最大值,因此直接使用这些变量是不可行的。
什么是让 Java 调用 l
和 n
的每个值并获取 ArrayList 中的值以找到的最小值和最大值的有效方法这些值?
我会稍微简化一下。假设您有一个密钥依赖于 Integer
k
和 String
s
。使用
似乎是个好主意
Map<String, Object>
键是 k + " " + s
(或类似的东西)。
这是一个糟糕的想法,因为正如您已经意识到的那样,您必须遍历 整个 映射并使用 String.split
才能找到特定的条目k
值。这是非常低效的。
一种常见的解决方案是改用 Map<Integer, Map<String, Object>>
。您可以通过 map.get(3).get("foo")
获取关联到 k = 3, s = "foo"
的对象。您还可以通过执行 map.get(3).values()
.
获取与 3
关联的所有对象
这种方法的缺点是添加到地图上有点麻烦。在 Java 8 你可以做到
map.computeIfAbsent(3, k -> new HashMap<String, Object>()).put("foo", "bar");
Google Guava's Table
接口消除了使用这样的数据结构的痛苦。
在 Java 8 中,您可以使用 DoubleSummaryStatistics 并执行如下操作:
final DoubleSummaryStatistics stats =
Flkn.entrySet().stream().filter(e -> e.getKey().matches("T_[0-9]+_" + k + "_[0-9]+"))
.flatMapToDouble(e -> e.getValue().stream().mapToDouble(Double::doubleValue))
.summaryStatistics();
System.out.println(stats.getMax());
System.out.println(stats.getMin());
filter
只保留您需要的条目; flatMapToDouble
合并您的列表;和 summaryStatistics
以获得最小值和最大值。
如果您绝对必须处理这样的问题 "smart keys",对于基于其部分的任何类型的处理,您首先需要函数来提取这些部分的值:
final static Function<String, Integer> EXTRACT_K = s -> Integer.parseInt(s.replaceAll("T_\d+_(\d+)_\d+", ""));
final static Function<String, Integer> EXTRACT_L = s -> Integer.parseInt(s.replaceAll("T_(\d+)_\d+_\d+", ""));
final static Function<String, Integer> EXTRACT_N = s -> Integer.parseInt(s.replaceAll("T_\d+_(\d+)_\d+", ""));
这些函数分别应用于键 return k
、l
或 n
(如果有人知道更优雅的方法,请发表评论或编辑)。
为了尽可能更有效(不是遍历整个地图,而是只遍历它的一部分),建议从 HashMap
切换到 SortedMap
的任何实现,并根据存储的值进行排序在智能钥匙中:
final static Comparator<String> CMP
= Comparator.comparing(EXTRACT_K)
.thenComparing(EXTRACT_L)
.thenComparing(EXTRACT_N);
SortedMap<String, List<Double>> map = new TreeMap<>(CMP);
这样你会得到一张地图,其中条目将首先按 k
排序,然后按 l
,最后按 n
排序。现在可以使用以下方法将所有列表映射到给定的 k
:
int k = 1;
Collection<List<Double>> lists
= map.subMap(String.format("T_0_%s_0", k), String.format("T_0_%s_0", k + 1)).values();
要获取 subMap
项目的最大值和最小值,获取其值流,将其转换为 DoubleStream
and use its .summaryStatistics()
,如下所示:
DoubleSummaryStatistics s
= subMap.values().stream()
.flatMapToDouble(vs -> vs.stream().mapToDouble(Double::doubleValue))
.summaryStatistics();
最后一部分是检查值是否存在:
if (s.getCount() > 0) {
max = s.getMax();
min = s.getMin();
} else
// no values exist for a given k, thus max and min are undefined
我有一个 ArrayLists 的 HashMap 如下:
HashMap<String, ArrayList<Double>> Flkn = new HashMap<String, ArrayList<Double>>();
Flkn.put("T_"+l+"_"+k+"_"+n, new ArrayList());
l
、k
和 n
根据几个循环获取它们的值,因此它们的值会根据参数而变化。
在这种情况下,我想知道对于给定的 k 值,如何在相关的 ArrayList 中找到元素的最小值和最大值。 (请注意,长度或 ArrayLists 也取决于参数)
例如,假设我想知道 k=3
的 ArrayList 中的最小值和最大值。那么我正在寻找的是所有 l
和 n
的每个值都具有键 ("T_"+l+"_"+3+"_"+n)
的 ArrayList。这里的问题是我无法预测 l
和 n
的值,因为它们完全依赖于代码。另一个不方便的事情是我想从 l
和 n
获取它们的值的循环中获取最小值和最大值,因此直接使用这些变量是不可行的。
什么是让 Java 调用 l
和 n
的每个值并获取 ArrayList 中的值以找到的最小值和最大值的有效方法这些值?
我会稍微简化一下。假设您有一个密钥依赖于 Integer
k
和 String
s
。使用
Map<String, Object>
键是 k + " " + s
(或类似的东西)。
这是一个糟糕的想法,因为正如您已经意识到的那样,您必须遍历 整个 映射并使用 String.split
才能找到特定的条目k
值。这是非常低效的。
一种常见的解决方案是改用 Map<Integer, Map<String, Object>>
。您可以通过 map.get(3).get("foo")
获取关联到 k = 3, s = "foo"
的对象。您还可以通过执行 map.get(3).values()
.
3
关联的所有对象
这种方法的缺点是添加到地图上有点麻烦。在 Java 8 你可以做到
map.computeIfAbsent(3, k -> new HashMap<String, Object>()).put("foo", "bar");
Google Guava's Table
接口消除了使用这样的数据结构的痛苦。
在 Java 8 中,您可以使用 DoubleSummaryStatistics 并执行如下操作:
final DoubleSummaryStatistics stats =
Flkn.entrySet().stream().filter(e -> e.getKey().matches("T_[0-9]+_" + k + "_[0-9]+"))
.flatMapToDouble(e -> e.getValue().stream().mapToDouble(Double::doubleValue))
.summaryStatistics();
System.out.println(stats.getMax());
System.out.println(stats.getMin());
filter
只保留您需要的条目; flatMapToDouble
合并您的列表;和 summaryStatistics
以获得最小值和最大值。
如果您绝对必须处理这样的问题 "smart keys",对于基于其部分的任何类型的处理,您首先需要函数来提取这些部分的值:
final static Function<String, Integer> EXTRACT_K = s -> Integer.parseInt(s.replaceAll("T_\d+_(\d+)_\d+", ""));
final static Function<String, Integer> EXTRACT_L = s -> Integer.parseInt(s.replaceAll("T_(\d+)_\d+_\d+", ""));
final static Function<String, Integer> EXTRACT_N = s -> Integer.parseInt(s.replaceAll("T_\d+_(\d+)_\d+", ""));
这些函数分别应用于键 return k
、l
或 n
(如果有人知道更优雅的方法,请发表评论或编辑)。
为了尽可能更有效(不是遍历整个地图,而是只遍历它的一部分),建议从 HashMap
切换到 SortedMap
的任何实现,并根据存储的值进行排序在智能钥匙中:
final static Comparator<String> CMP
= Comparator.comparing(EXTRACT_K)
.thenComparing(EXTRACT_L)
.thenComparing(EXTRACT_N);
SortedMap<String, List<Double>> map = new TreeMap<>(CMP);
这样你会得到一张地图,其中条目将首先按 k
排序,然后按 l
,最后按 n
排序。现在可以使用以下方法将所有列表映射到给定的 k
:
int k = 1;
Collection<List<Double>> lists
= map.subMap(String.format("T_0_%s_0", k), String.format("T_0_%s_0", k + 1)).values();
要获取 subMap
项目的最大值和最小值,获取其值流,将其转换为 DoubleStream
and use its .summaryStatistics()
,如下所示:
DoubleSummaryStatistics s
= subMap.values().stream()
.flatMapToDouble(vs -> vs.stream().mapToDouble(Double::doubleValue))
.summaryStatistics();
最后一部分是检查值是否存在:
if (s.getCount() > 0) {
max = s.getMax();
min = s.getMin();
} else
// no values exist for a given k, thus max and min are undefined