Java三列键的Map

7
我需要一个地图,其中我的关键字应基于三列,例如 C1,C2,C3C1 优先级最高。 C2 的优先级次于 C1,而 C3 的优先级则次于 C2
如何在地图中创建关键字,以便如果有人要求有关 C1 的信息,我应该能够提供所有具有 C1 的值。 如果请求 C1 & C2,则我还应该能够返回所有的值。

4
可以给我们展示一些测试用例吗?你的输入和输出是什么? - Daniel Kaplan
2
问题不清楚。 - AmitG
这不是一个标准问题。让我们针对当前场景来解决这个问题以适应你的用途。请问C1、C2和C3的数据类型是什么?如果它们是整数,那么它们的范围是多少? - Saurabh
您能以表格格式共享C1、C2和C3的一些示例值吗?表格应包含列C1、C2和C3。 - Apurv
我不理解这个问题,但是请参考具有多个字段用于键和值的SortedMap如何实现具有多个键的Map? - James Waldby - jwpat7
9个回答

2
使用三个地图。
One Map<C1, V> and one Map<C2, V> and one Map<C3, V>. 

您可以将这三个地图封装成一个类,并实现您的方法。

2
您可以使用与数据库中的多列索引相同的策略,如果您的键列可以排序(即,在Java中,它们需要是Comparable),并且可以轻松地为除第一列以外的所有列定义最大和最小值。
以下是一个整数列的示例:
public class Key implements Comparable<Key> {
    int c1, c2, c3;

    private static final int c2_min = Integer.MIN_VALUE;
    private static final int c2_max = Integer.MAX_VALUE;
    private static final int c3_min = Integer.MIN_VALUE;
    private static final int c3_max = Integer.MAX_VALUE;

    @Override
    public int compareTo(Key o) {
        if (c1!=o.c1) return Integer.compare(c1, o.c1);
        if (c2!=o.c2) return Integer.compare(c2, o.c2);
        return Integer.compare(c3, o.c3);
    }

    // constructor, equals, ...

}

然后,您可以像这样获取k1中的所有条目:c1

map.subMap(new Key(k1, Key.c2_min, 0), new Key(k1, Key.c2_max, 0));

同样地,使用前两列:
map.subMap(new Key(k1, k2, Key.c3_min), new Key(k1, k2, Key.c3_max));

谢谢,我有问题,我的类型是byte[]。我该如何定义MAX和MIN值? - Avinash
假设有一个字节比较器,你可以使用MIN = new byte [0]。对于MAX,如果您有最大数组大小,请使用它并使用Byte.MAX_VALUE初始化所有元素。否则,您必须选择一些实例(定义为static final),并在compareTo中使用==显式检查它。最后,根据您的应用程序,null也可能作为最大值工作,通过在compareTo中明确考虑它。 - jop

0
一个三级索引,其中高级键可以用于访问所有低级键和对象,将需要一个三级映射。
class ThreeLevelMap<K1,K2,K3,V>
{
    private Map<K1,Map<K2,Map<K3,V>>> store = new HashMap<K,Map<K2,Map<K3,V>>>();
    ...
    public V put(K1 key1, K2 key2, K3 key3, V value) { ... }
    public V get(K1 key1, K2 key2, K3 key3) { ... }

    public static class TLMEntry<K1,K2,K3,V>
    {
    ...
    }
    public Collection<TLMEntry<K1,K2,K3,V>> get(K1 key1, K2 key2) { ... }
    public Collection<TLMEntry<K1,K2,K3,V>> get(K1 key1) { ... }
}

这是一个基本的框架,但应该能让你朝着正确的方向前进。


0

这似乎更像是一个数据库问题。如果您有一个类似下面结构的表的数据库:

CREATE TABLE MyMap (
    id IDENTITY PRIMARY KEY,
    c1 int, -- Change data types as needed.
    c2 int,
    c3 int,
    v  int);

然后,您只需对其发出SELECT语句即可。您可能想使用任何内存中的Java数据库。

如果您不想这样做,您可以通过编写容器类值类在Java中纯粹地进行等效功能:

class Cdata {
    private int c1;
    private int c2;
    private int c3;
    private int v;
    // Constructors and getters elided.
    public boolean match(int c1) {
        return this.c1 == c1;
    }
    public boolean match(int c1, int c2) {
        return match(c1) && this.c2 == c2;
    }
    public boolean match(int c1, int c2, int c3) {
        return match(c1, c2) && this.c3 == c3;
    }
}

接下来,创建一个列表并使用功能编程库中的过滤方法。或者等待Java 8 lambdas。使用一个Map<Integer,Map<Integer,Map<Integer,Integer>>>>太令人困惑了。


0

您可以使用TreeMap来实现您的用例。我假设以下内容:

您的三列映射到3个递增的整数值,即

C1 = 1,C2 = 2,C3 = 3

其中C1 = 1是最高优先级,C2 = 2是次高优先级,依此类推。

注意:您的键不一定总是整数,如果您为您的TreeMap提供了适当的比较器,则可以使用任何类型。

有了这个设置,您可以执行以下操作:

TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>();
treeMap.put(1, "One");
treeMap.put(2, "two");
treeMap.put(3, "three");

List<String> list = getMappedValues(treeMap, 1);// returns One, Two, Three
//List<String> list = getMappedValues(treeMap, 2);// returns Two, Three
//List<String> list = getMappedValues(treeMap, 3);// returns Three
//List<String> list = getMappedValues(treeMap, 4);// returns null
if(list != null){
    //do something with the list of values
}

private static List<String> getMappedValues(TreeMap<Integer, String> map, Integer key) {
    Entry<Integer, String> e = map.ceilingEntry(key);
    if(e == null){
        return null;
    }
    List<String> list = new ArrayList<String>();
    while(e != null){
        list.add(e.getValue());
        key = e.getKey();
        e = map.higherEntry(key);
    }
    return list;
}

0

通过“优先级”,我想你指的是通常所说的主键、次键和第三键。

如果它们都是字符串字段,将它们连接成一个单独的字符串,并将其用作键。在您的情况下,键是C1+C2+C3(其中“+”表示字符串连接)。


但是你如何仅获取与C1对应的值或仅获取与C1和C2对应的值呢? - Saurabh

0

一个 Map 对于一个键总是只返回一个值。你不能根据键类的内容返回多个值。

简单的方法是为每种键类型保留一个单独的 Map,并根据传递的键返回相应的结果。


0

从我们如果可以访问数据库时如何处理这个问题上得到灵感。

假设我们有一个包含列 C1、C2、C3 和 Value 的表。

并且给出以下查询模式的要求:

  1. select * from tbl where C1 = "input1";
  2. select * from tbl where C1 = "input1" and C2 = "input2";
  3. select * from tbl where C1 = "input1" and C2 = "input2" and C3 = "input3";

在这种情况下,最好使用一个按(C1、C2、C3)特定顺序排序的多列索引 - 它将在内部创建3个单独的索引,如下所示:

  • 索引1 - C1(适用于类型1的查询。)
  • 索引2 - C1和C2(适用于类型2的查询。)
  • 索引3 - C1和C2和C3(适用于类型3的查询。)

我们可以在Java中遵循类似的策略 - 定义3个映射:

  • Map1 - Map<C1, Set>
  • Map2 - Map<C1+C2, Set> (这里的键是C1和C2的字符串值的连接)
  • Map3 - Map<C1+C2+C3, Set> (这里的键是C1、C2和C3的字符串值的连接)

因此,根据传递的键来获取查询,我们选择适当的映射。

  • get(K1) - 我们将从Map1中获取
  • get(K1, K2) - 我们将从Map2中获取
  • get(K1, K2, K3) - 我们将从Map3中获取

请注意,这将要求我们在所有三个映射中插入/删除以注册新数据并删除现有数据。


0

private class C {

    public C() {
        Map <Object ,String> ObjectC =new HashMap<Object, String>();
    }
}

private class B {

    public B() {
        Map <Object ,C> ObjectB =new HashMap<Object, C>();
    }
}

private class A {

    public A() {
        Map <Object ,B> ObjectA =new HashMap<Object, B>();
    }
}

因此,这可以为您承诺一个美丽的结构,您无需进一步进行更多工作,因为您可以获取A的所有内容

MapVar.ObjectA.get(C1);

如果C1和C2都已给出,您可以调用。
MapVar.ObjectA.get(C1).ObjectB.get(C2);

如果给定了C1、C2和C3,你可以调用:
MapVar.ObjectA.get(C1).ObjectB.get(C2).ObjectC.get(C3);;

然后您可以简单地遍历该映射并获取值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接