Java 可以将一系列键映射到一个值的数据结构

Java 可以将一系列键映射到一个值的数据结构,java,dictionary,data-structures,range-map,Java,Dictionary,Data Structures,Range Map,我试图找到一种数据结构,它从一系列值中提取一个特定值,并将其映射到一个键 例如,我有以下条件: 从1到2.9,我想把它映射到A 从4到6,我想把它映射到B 从6.5到10,我想把它映射到C 我有一个值5,我想把它映射到一个键。基于以上条件,我应该把它映射到B Java中是否有任何数据结构可以推荐给我来解决这个问题 目前我使用的哈希表只能将值映射到键。我试图将值的范围映射到哈希表中存在的特定值。但是,我陷入了将值的范围映射到特定值的过程中。现在我尝试用另一种方法将值的范围映射到一个键。有人知道我如

我试图找到一种数据结构,它从一系列值中提取一个特定值,并将其映射到一个键

例如,我有以下条件:

  • 从1到2.9,我想把它映射到A
  • 从4到6,我想把它映射到B
  • 从6.5到10,我想把它映射到C
  • 我有一个值5,我想把它映射到一个键。基于以上条件,我应该把它映射到B

    Java中是否有任何数据结构可以推荐给我来解决这个问题

    目前我使用的哈希表只能将值映射到键。我试图将值的范围映射到哈希表中存在的特定值。但是,我陷入了将值的范围映射到特定值的过程中。现在我尝试用另一种方法将值的范围映射到一个键。有人知道我如何解决这个问题吗

    编辑:


    多亏了Martin Ellis,我决定使用TreeMap来解决这个问题。

    其中一种方法是,使用列表实现中的一个作为键的值

    map.put("A", ArrayList<Integer>);
    
    map.put(“A”,数组列表);
    
    只需在地图中列出一个值即可

    Map<String, List<Double>> map = new HashMap<String, List<Double>>();
    
    Map Map=newhashmap();
    
    还有一个建议:

    除非希望同步访问,否则不要使用哈希表

    编辑:


    哈希表方法是同步的,即没有两个线程可以在一个时间点访问这些方法。HashMap方法不同步。如果使用Hashtable,将对性能造成影响。使用HashMap可获得更好的性能。

    A
    HashMap
    不适用于将范围映射到值,除非您找到一种方法为其中的范围和单个值生成匹配的hashcode。但下面的方法可能是您所寻找的

    public class RangeMap {
        static class RangeEntry {
            private final double lower;
            private final double upper;
            private final Object value;
            public RangeEntry(double lower, double upper, Object mappedValue) {
                this.lower = lower;
                this.upper = upper;
                this.value = mappedValue;
            }
            public boolean matches(double value) {
                return value >= lower && value <= upper;
            }
            public Object getValue() { return value; }
        }
    
        private final List<RangeEntry> entries = new ArrayList<RangeEntry>();
        public void put(double lower, double upper, Object mappedValue) {
            entries.add(new RangeEntry(lower, upper, mappedValue));
        }
        public Object getValueFor(double key) {
            for (RangeEntry entry : entries) {
                if (entry.matches(key))
                    return entry.getValue();
            }
            return null;
        }
    }
    
    它的效率不是很高,因为它只是在一个列表上进行迭代,如果在列表中放入冲突的范围,它将不会在该状态下抱怨。将只返回它找到的第一个


    注意:这样的映射就是将一系列键映射到一个值

    您的范围是否不重叠?如果是这样,您可以使用树形图:

    TreeMap<Double, Character> m = new TreeMap<Double, Character>();
    m.put(1.0, 'A');
    m.put(2.9, null);
    m.put(4.0, 'B');
    m.put(6.0, null);
    m.put(6.5, 'C');
    m.put(10.0, null);
    
    更多结果包括:

    0.9 null
    1.0 A
    1.1 A
    2.8 A
    2.9 A
    3.0 null
    6.4 null
    6.5 C
    6.6 C
    9.9 C
    10.0 C
    10.1 null
    

    这似乎是使用树结构的自然情况

    不幸的是,实现
    java.util.Map
    接口是不实际的,因为它指定了一个方法来返回所有键,并且在您的情况下,理论上有大量的键

    树的每个节点都应该有一个最小键、一个最大键和一个与该范围关联的值。然后,您可以拥有指向表示下一个较高和下一个较低范围(如果存在)的节点的链接。比如:

    public class RangeMap<K extends Comparable<K>, V> {
        protected boolean empty;
        protected K lower, upper;
        protected V value;
        protected RangeMap<K, V> left, right;
    
        public V get(K key) {
            if (empty) {
                return null;
            }
    
            if (key.compareTo(lower) < 0) {
                return left.get(key);
            }
    
            if (key.compareTo(upper) > 0) {
                return right.get(key);
            }
    
            /* if we get here it is in the range */
            return value;
        }
    
        public void put(K from, K to, V val) {
            if (empty) {
                lower = from;
                upper = to;
                value = val;
                empty = false;
                left = new RangeMap<K,V>();
                right = new RangeMap<K,V>();
                return;
            }
    
            if (from.compareTo(lower) < 0) {
                left.put(from, to, val);
                return;
            }
    
            if (to.compareTo(upper) > 0) {
                right.put(from, to, val);
                return;
            }
    
            /* here you'd have to put the code to deal with adding an overlapping range,
               however you want to handle that. */
        }
    
        public RangeMap() {
            empty = true;
        }
    }
    
    公共类范围图{
    受保护布尔值为空;
    保护K下部,上部;
    保护V值;
    保护范围图左,右;
    公共V get(K键){
    if(空){
    返回null;
    }
    if(键比较(下)<0){
    向左返回。获取(键);
    }
    如果(键比较(上)>0){
    返回右键。获取(键);
    }
    /*如果我们到了这里,它就在范围之内*/
    返回值;
    }
    公开作废认沽权(K from,K to,V val){
    if(空){
    较低=来自;
    上限=至;
    值=val;
    空=假;
    左=新的范围映射();
    右=新的范围映射();
    返回;
    }
    如果(从比较到(较低)<0){
    左。放置(从,到,val);
    返回;
    }
    如果(与(上部)相比>0){
    对。放置(从,到,val);
    返回;
    }
    /*在这里,您必须使用代码来处理添加重叠范围的问题,
    不管你想怎么处理*/
    }
    公共范围地图(){
    空=真;
    }
    }
    

    如果您需要比树提供的更快的查找速度,您可能需要查看跳过列表或开发自己的哈希函数之类的内容。

    这种类型的数据结构称为。(Wikipedia页面仅显示间隔可能重叠的情况,但可以想象这样一种情况:在添加新间隔时,您希望删除任何重叠间隔的映射。在谷歌上搜索实现,看看是否有适合您需要的任何实现。

    Guava现成的专门解决方案:

    RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
    rangeMap.put(Range.closed(1, 100), "foo"); // {[1, 100] => "foo"}
    rangeMap.put(Range.open(3, 6), "bar"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 100] => "foo"}
    
    rangeMap.get(42); // returns "foo"
    
    RangeMap RangeMap=TreeRangeMap.create();
    rangeMap.put(Range.closed(1100),“foo”);/{[1100]=>“foo”}
    rangeMap.put(Range.open(3,6),“bar”);/{[1,3]=>“foo”,(3,6)=>“bar”,[6100]=>“foo”}
    rangeMap.get(42);//返回“foo”
    
    我认为Apache commons包含了一些解决此问题的解决方案


    使用SubnetUtils的SubnetUtils.SubnetInfo

    Hi。值的范围是双精度的,可以有许多小数位。在这种情况下,我应该将所有可能的值(双精度)添加到哈希表/映射的双精度列表中吗?但是如何从哈希表/映射检索键?可以使用keySet()若您使用HashMap.Iterate on keySet,标识key是否存在,若存在get values List,若不存在则创建新的List和key。我使用的是hashtable和以前使用的get()获取键。虽然我的值是一个双精度列表,但我可以在这种情况下使用相同的方法吗?是的,您可以。如果该键没有值,那么您可以创建新的列表并添加它。顺便问一下,为什么要坚持使用哈希表而不是哈希映射?嗨。值的范围是双精度的,可以有许多小数位。在这种情况下,我应该添加吗将所有可能的值(以double形式)放入double列表中,该列表是哈希表/映射的值?谢谢!同步访问是什么意思?我建议不要使用
    hashtable
    。如果您需要处理并发性,如果您不担心并发性,最好使用如图所示的
    ConcurrentHashMap
    (即,一个简单的Java程序,没有
    0.9 null
    1.0 A
    1.1 A
    2.8 A
    2.9 A
    3.0 null
    6.4 null
    6.5 C
    6.6 C
    9.9 C
    10.0 C
    10.1 null
    
    public class RangeMap<K extends Comparable<K>, V> {
        protected boolean empty;
        protected K lower, upper;
        protected V value;
        protected RangeMap<K, V> left, right;
    
        public V get(K key) {
            if (empty) {
                return null;
            }
    
            if (key.compareTo(lower) < 0) {
                return left.get(key);
            }
    
            if (key.compareTo(upper) > 0) {
                return right.get(key);
            }
    
            /* if we get here it is in the range */
            return value;
        }
    
        public void put(K from, K to, V val) {
            if (empty) {
                lower = from;
                upper = to;
                value = val;
                empty = false;
                left = new RangeMap<K,V>();
                right = new RangeMap<K,V>();
                return;
            }
    
            if (from.compareTo(lower) < 0) {
                left.put(from, to, val);
                return;
            }
    
            if (to.compareTo(upper) > 0) {
                right.put(from, to, val);
                return;
            }
    
            /* here you'd have to put the code to deal with adding an overlapping range,
               however you want to handle that. */
        }
    
        public RangeMap() {
            empty = true;
        }
    }
    
    RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
    rangeMap.put(Range.closed(1, 100), "foo"); // {[1, 100] => "foo"}
    rangeMap.put(Range.open(3, 6), "bar"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 100] => "foo"}
    
    rangeMap.get(42); // returns "foo"