按日期对 HashMap 进行排序
Posted
技术标签:
【中文标题】按日期对 HashMap 进行排序【英文标题】:Sorting a HashMap by date 【发布时间】:2015-12-04 12:15:18 【问题描述】:在 Java 类中,我有一个按日期重新排序现有 HashMap 的方法。 HashMap 的类型为<String, Object>
,其中 Object 包含一个名为 expPayDate 的字段,而键字符串是一个序列号,变成了一个字符串。所以我需要遍历 sourceMap 中的项目并找到具有最新日期的项目然后以正确的顺序将其复制到 tempMap 中。我的问题是确定具有最新日期的项目的最佳方法是什么。
【问题讨论】:
HashMaps 没有顺序 您应该查看已排序的地图。 docs.oracle.com/javase/8/docs/api/java/util/SortedMap.html 你的泛型类型真的是Object
还是我们可以假设它是MyClass
之类的东西?我在问,因为Object
在它的接口方法中没有允许我们获取expPayDate
,而MyClass
可能包含类似getExpPayDate()
的东西。
坚持使用非 Java 8 解决方案,因为我们还不能使用 Java 6 以外的任何东西。将您的 Map 重新定义为 TreeMap 或使用 Comparator 对我来说最有意义。如果您有一个列表形式的项目集合,我想知道 List 是否会更好地满足您的需求。根据您要执行的操作,您可能希望查看 each of the Java Collections do for you 的内容。关于将 Comparator 与 List 结合使用,I blogged about that in January.
【参考方案1】:
最好的办法是使用带有Comparator 接口的SortedMap。
这是一个例子:
public SortedMap<String, Object> getSortedMap(Map<String, Object> originalMap)
SortedMap<String, Object> tmpMap = new TreeMap<String, Object>(new Comparator<String>()
@Override
public int compare(String key1, String key2)
//logic for comparing dates
);
tmpMap.putAll(originalMap);
return tmpMap;
【讨论】:
值得注意的是,我们在 TreeMap 中使用的 Comparator 用于比较keys
,而不是 values
,也不是 dates
。我们需要每次使用 key 来获取 value,读取它的 date 属性。然后我们可以使用相同的第二个键和比较日期。
@Pshemo 不错。我将答案的泛型类型更改为使用 String 而不是 Object。
您也可以将compare
方法参数的名称更改为key1
和key2
。【参考方案2】:
使用 TreeMap 而不是 HashMap。插入时会自动排序。
Map< Date, Object> m = new TreeMap< Date, Object>();
或者,如果您有一个现有的 HashMap 并希望基于它创建一个 TreeMap,请将其传递给构造函数:
Map< Date, Object> sortedMap = new TreeMap< Date, Object>(m);
希望对你有所帮助。
【讨论】:
日期是值的属性,而不是键。 我使用 HashMap 是因为我根据 ViewEntryCollection 的排序顺序加载它,但为了便于访问,我在 HashMap 中使用它并带有序号。我这样做是因为我使用 HashMap 作为重复控件的数据源。所以我可以使用重复中的索引来获取正确的 HashMap。因此,当我启动 Hashmap 时,它的顺序是正确的,但是如果我向 HashMap 添加一个新的“行项目”,它就会出现在列表的末尾。我不想从磁盘重新加载 HashMap。 所以我的解决方案是从 HashMap 中读取每个“PaymentItem”并将其存储在一个 TreeMap为简单起见,我假设您的地图类型更像Map<String, MyClass> map
,其中MyClass
的方法类似于getDate()
,它返回expPayDate
。
我的问题是确定最新日期的项目的最佳方法是什么。
如果您想查找 value 包含最大日期的单个地图条目 您不需要对整个地图进行排序,这最多会给您 O(n*logn )。您需要的是对 map 中的所有元素进行简单迭代,并将它们与当前最大值进行比较,这将是 O(n) 操作。
您可以使用stream()
(Java 8 中添加的功能)及其max
方法。此方法需要Comparator
,您可以通过使用comparing
方法并传递lambda 表达式轻松创建一个,该表达式将返回值,比较时应使用该值。
所以你的代码看起来像
//import java.util.Map.Entry;
Optional<Entry<String, MyClass>> max = map.entrySet().stream()
.max(Comparator.comparing(e -> e.getValue().getDate()));
Entry<String, MyClass> entry = max.get();
MyClass maxMC = entry.getValue();
如果您不能使用 Java 8,您可以编写自己的方法来迭代元素并找到最大值。这种方法看起来像
public static <T> T max(Iterable<T> iterable, Comparator<T> comp)
Iterator<T> it = iterable.iterator();
T max = null;
if (it.hasNext())
max = it.next();
while (it.hasNext())
T tmp = it.next();
if (comp.compare(max, tmp) < 0)
max = tmp;
return max;
你可以像使用它一样
Comparator<Entry<String, MyClass>> myComparator = new Comparator<Entry<String, MyClass>>()
@Override
public int compare(Entry<String, MyClass> o1, Entry<String, MyClass> o2)
return o1.getValue().getDate().compareTo(o2.getValue().getDate());
;
Entry<String, MyClass> maxEntry = max(map.entrySet(), myComparator);
MyClass max = maxEntry.getValue();
【讨论】:
OP 的问题是关于 JEE 实现,具体是 1.6(目前)。 XPages 运行时(还)不能从任何 Java 8 实现中受益。我收回了我的否决票,因为这对于非 XPages 开发人员来说并不明显,并且是平台所独有的,但我相信这为所有 Java 实现提供了一些合理的优点,并强调了将运行时更新到更高版本的 Java 的必要性版本。很好的输入,但@Bill 将无法使用它。 @EricMcCormick 如果问题仅出在 Java 8 上,那么这意味着没有真正的问题,因为该解决方案可以轻松地重写为旧版本的 Java。我的回答的主要部分是表明我们实际上不需要创建分离的排序映射(这将是 O(n*logn) 位,以防找到最大值,我们只需遍历所有元素一次,即 O(n) )。我将为旧版本的 Java 重写我的代码。 别担心,我同意。这是一个完全合理的答案……对于大多数情况;我对该平台的不满之一(目前,我们已经得到承诺会推出一个更新的 JVM)。【参考方案4】:调用Map的entrySet()
方法获取所有Entries
创建自定义 Comparator
以根据值对条目进行排序
将Entry
设置为List
通过传递您的值比较器,使用Collections.sort()
方法对条目列表进行排序
通过按排序顺序添加条目来创建LinkedHashMap
。
看示例代码@Sort HasMap by value
【讨论】:
不要对未引用的文本使用引号格式。【参考方案5】:如果您只需要最小或最大日期,一个简单的 for each 循环可能就足够了:
Date maxDate = null;
for (Entry<String, Object> item: hashMap.entrySet())
if (maxDate == null || maxDate before((Date)item.getValue()))
maxDate = (Date)item.getValue();
这种方式的复杂度仅为 O(n),并且插入和删除操作比使用 sortedMap
便宜。无论如何,我认为 patstuart 的建议(使用sortedMap
)更优雅。
【讨论】:
【参考方案6】:正确的解决方案取决于您的性能限制。
如果您的问题只是找到具有最新日期的项目,那么如果 O(n) 性能还可以,您可以扫描 HashMap 中的 values() 并找到最小值。
这取决于相对于对数据结构的其他访问,您需要多久执行一次此操作。根据您对该数据结构的访问模式,使用 SortedMap 或使用诸如 PriorityQueue 之类的辅助数据结构(在日期上充当堆)是完全合理的。
【讨论】:
以上是关于按日期对 HashMap 进行排序的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 中按字母顺序对 Hashmap 值类型进行排序