【问题标题】:Java data structure that acts like TreeMap + Hash?像 TreeMap + Hash 一样的 Java 数据结构?
【发布时间】:2013-02-17 10:26:30
【问题描述】:

我需要将键值对输入到数据结构中,这样我就可以按键的升序检索它们——但它们可能是许多具有相同值的键。

因此,如果 kv 对是 {10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i} 我会需要按以下顺序检索值:a、b、c、d、e、f、g、h、i。 JAVA API 中是否有任何数据结构支持这一点?

我尝试使用 TreeMap,因为它使它们保持有序,这允许我使用 TreeMap.lastKey() 来检索当前最高的键,但我不知道它会覆盖地图中已经存在的任何重复键。我需要一些不会覆盖的东西(类似于 HASH),但也允许我按排序顺序检索它们——这存在吗?

谢谢!

【问题讨论】:

  • 所以一个带有List 值的Map 将与一个带有多个值的键相关——我相信我可以将Maps 存储在一个ArrayList 中,对吗?
  • A HashMap 也会覆盖重复的键。我怀疑这不是你真正的意思?另外,您说键的升序,但您的示例是降序的?您的意思是键的降序和值的升序吗?

标签: java list data-structures hashmap treemap


【解决方案1】:

不幸的是,您可能找不到支持相同键的多个值的结构。正如 Dilum 所说,“MultiMap”或“Multi-Valued Maps”有几种实现方式可以很好地工作。

除了 Guava 的 TreeMultiMap,还有 Spring Framework 的 MultiValueMap 和 Apache Common 的 MultiValueMap

Spring 实现的一个例子是:

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;


public class MultiValueMapExample {

    public static void main(String[] args) {
        // 10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i
        MultiValueMap<Integer, String> map = new LinkedMultiValueMap<Integer, String>();
        map.add(10, "a");
        map.add(10, "b");
        map.add(9, "c");
        map.add(8, "d");
        map.add(8, "e");
        map.add(8, "f");
        map.add(8, "g");
        map.add(4, "h");
        map.add(2, "i");

        System.out.println(map.toString());
        // {10=[a, b], 9=[c], 8=[d, e, f, g], 4=[h], 2=[i]}
    }
}

您可以通过以下 Maven 依赖项添加 Spring-Core 来使用它:

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.1.RELEASE</version>
        </dependency>

如果您在项目中获取这些库中的任何一个时需要帮助,请随时发表评论/联系我。

更新 1

事实证明,没有一种方便的方法可以从原始 API 中过滤/排序。我在下面包含了一个简单的过滤器功能,应该可以解决问题。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;


public class MultiValueMapExample {

    public static void main(String[] args) {
        // 10-a, 10-b, 9-c, 8-d, 8-e, 8-f, 4-g, 4-h, 2-i
        MultiValueMap<Integer, String> map = new LinkedMultiValueMap<Integer, String>();
        map.add(8, "g");
        map.add(4, "h");
        map.add(10, "a");
        map.add(10, "b");
        map.add(9, "c");
        map.add(8, "d");
        map.add(8, "e");
        map.add(8, "f");

        map.add(2, "i");

        System.out.println(map.toString());
        // {8=[g, d, e, f], 4=[h], 10=[a, b], 9=[c], 2=[i]}

        MultiValueMap<Integer, String> filteredMap = filter(5, map);
        System.out.println( filteredMap.toString() );
        // {10=[a, b], 9=[c], 8=[g, d, e, f], 4=[h], 2=[i]}

    }

    public static MultiValueMap<Integer, String> filter(int numberOfResults, MultiValueMap<Integer, String> map){
        MultiValueMap<Integer, String> result = new LinkedMultiValueMap<Integer, String>();

        List<Integer> keys = new ArrayList<Integer>(map.keySet());
        Collections.sort(keys, Collections.reverseOrder());

        for(Integer key : keys){
            if( result.size() <= numberOfResults ){
                result.put(key, map.get(key));
            }else{
                break;
            }
        }

        return result;

    }
}

【讨论】:

  • 大卫,是否可以按键的顺序检索多集中的项目?例如,我有一个大小为 5 的数组,我想获取具有 5 个最高键的值。在这种情况下,我会选择 a、b、c、d 和 e。这在任何实现中都可能吗?如果是这样,我非常希望您能帮助我将库纳入我的项目,谢谢!
  • 是的,您应该能够通过使用具有可比实现的 Collections.sort 来实现。您是要根据最高的键值还是值最多的键来做?
  • 原来过滤地图有点棘手。我添加了一个带有简单过滤方法的更新示例。它应该工作得很好,除非你有一个大数据集或其他东西
  • @kpscript 任何答案对您有帮助吗?如果是,请投票:D
【解决方案2】:

Java 中通常使用的术语是“MultiMap”。比如看Guava's TreeMultiMap

接口和任何实现都不是该标准 API 的一部分。

【讨论】:

    猜你喜欢
    • 2013-08-12
    • 2010-11-18
    • 2010-09-23
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    相关资源
    最近更新 更多