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中是否有任何数据结构可以推荐给我来解决这个问题 目前我使用的哈希表只能将值映射到键。我试图将值的范围映射到哈希表中存在的特定值。但是,我陷入了将值的范围映射到特定值的过程中。现在我尝试用另一种方法将值的范围映射到一个键。有人知道我如
多亏了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.SubnetInfoHi。值的范围是双精度的,可以有许多小数位。在这种情况下,我应该将所有可能的值(双精度)添加到哈希表/映射的双精度列表中吗?但是如何从哈希表/映射检索键?可以使用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"