寻找“连锁地图” Java 中的实现

发布于 2024-10-08 06:08:04 字数 383 浏览 4 评论 0原文

我需要从键列表到值的映射。我知道我可以像这样编写自己的代码:

Map<Person, Map<Daytime, Map<Food, Integer>>> eaten = ...;

现在我想要一些 getput 方法,如下所示:

Integer numberOfEggsIAteInTheMorning = eaten.get(me, morning, scrambledEggs);
eaten.put(me, evening, scrambledEggs, 1);

你知道有这样的现有类吗API?我自己也懒得写了。 ;)

I need a mapping from a list of keys to a value. I know I could write my own code like this:

Map<Person, Map<Daytime, Map<Food, Integer>>> eaten = ...;

Now I want to have some get and put methods like these:

Integer numberOfEggsIAteInTheMorning = eaten.get(me, morning, scrambledEggs);
eaten.put(me, evening, scrambledEggs, 1);

Do you know of an existing class that has this kind of API? I'm too lazy of writing it myself. ;)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

樱花坊 2024-10-15 06:08:04

如果您寻找更通用的方法,并且可能有超过 2 或 3 个“链步骤”,我建议应用一些不同的结构方法,而不是坚持仅使用基本集合类。我觉得如果正确应用,复合模式可能是正确的选择。

编辑:由于请求示例

完整的示例会有点耗时,所以让我用肮脏的Java/伪代码混合来解释我的想法(我什至不确定我是否错过了一些东西! !)。假设我们有 BaseMap 类:

abstract class BaseMap { 
    public abstract Object getValue(Object.. keys);
    public abstract void putValue(Object value, Object.. keys);
}

那么我们可以有 ObjectMap,它将成为复合结构的“叶子”:

class ObjectsMap extends BaseMap {
    private Map<Object, Object> map = new [...]
    public Object getValue(Object.. keys) {
        // assert that keys.length == 1
        return map.get(keys[0]);
    }
    public void putValue(Object value, Object.. keys) {
        // assert that keys.length = 1
        map.put(keys[0], value);
    }
}

实际的复合结构将如下所示:

class CompositeMap extends BaseMap {
    private Map<Object, BaseMap> compositeMaps = new [...]
    public Object getValue(Object.. keys) {
        // assert that keys.length > 1
        return compositeMap.get(keys[0]).getValue(/* System.arrayCopy => subset of elements {keys_1, .. ,keys_max} */);
    }
    public void putValue(Object value, Object.. keys) {
        // assert keys.length > 1
        BaseMap newMap = null;
        if (keys.length = 2) -> newMap = new ObjectsMap()
        else newMap = new CompositeMap();
        newMap.putValue(value, /*subset of keys {keys_1, .. , keys_max}*/);

    }
}

If you look for a more generic approach, and you might have more than 2 or 3 'chain steps', I would suggest in applying some different structural approach, rather than sticking to using only basic collection classes. I have feeling that Composite Pattern could be the right choice if it's correctly applied.

EDIT: due to example requested

The full example would be somewhat time consuming, so let me just explain my idea with dirty Java/pseudocode mix (I'm not even sure if I've missed something!!!). Let's consider we have class BaseMap:

abstract class BaseMap { 
    public abstract Object getValue(Object.. keys);
    public abstract void putValue(Object value, Object.. keys);
}

Then we could have ObjectMap that would be the 'leaf' of our composite structure:

class ObjectsMap extends BaseMap {
    private Map<Object, Object> map = new [...]
    public Object getValue(Object.. keys) {
        // assert that keys.length == 1
        return map.get(keys[0]);
    }
    public void putValue(Object value, Object.. keys) {
        // assert that keys.length = 1
        map.put(keys[0], value);
    }
}

And the actual composite would be as such:

class CompositeMap extends BaseMap {
    private Map<Object, BaseMap> compositeMaps = new [...]
    public Object getValue(Object.. keys) {
        // assert that keys.length > 1
        return compositeMap.get(keys[0]).getValue(/* System.arrayCopy => subset of elements {keys_1, .. ,keys_max} */);
    }
    public void putValue(Object value, Object.. keys) {
        // assert keys.length > 1
        BaseMap newMap = null;
        if (keys.length = 2) -> newMap = new ObjectsMap()
        else newMap = new CompositeMap();
        newMap.putValue(value, /*subset of keys {keys_1, .. , keys_max}*/);

    }
}
三月梨花 2024-10-15 06:08:04

您可以使用 org.apache.commons.collections.keyvalue.MultiKey 来实现:Map

You can use org.apache.commons.collections.keyvalue.MultiKey for that: Map<Multikey, Object>

浪漫人生路 2024-10-15 06:08:04

实现通用的链式地图是很困难的。

类的声明会是什么样子? (您不能拥有可变数量的类型参数。

class ChainedMap<K1..., V>

另一种选择是使用一个 ChainedMapUtil 类来递归执行 put / get。

这是一个递归 get 的示例。(尽管解决方案相当丑陋)我必须说。)

import java.util.*;

public class Test {

    public static Object chainedGet(Map<?, ?> map, Object... keys) {

        Object k = keys[0];

        if (!map.containsKey(k)) return null;

        if (keys.length == 1) return map.get(k);

        Object[] tailKeys = Arrays.copyOfRange(keys, 1, keys.length);
        return chainedGet((Map<?,?>) map.get(k), tailKeys);        
    }

    public static void main(String[] arg) {

        Map<String, String> m1 = new HashMap<String, String>();
        m1.put("ipsum", "dolor");

        Map<Integer, Map<String, String>> m2 =
                new HashMap<Integer, Map<String, String>>();
        m2.put(17, m1);

        Map<String, Map<Integer, Map<String, String>>> chained =
            new HashMap<String, Map<Integer, Map<String, String>>>();
        chained.put("lorem", m2);

        System.out.println(chainedGet(chained, "lorem", 17, "ipsum")); // dolor
        System.out.println(chainedGet(chained, "lorem", 19, "ipsum")); // null
    }
}

It would be hard to implement a general chained map.

How would the declaration of the class look like? (You can't have a variable number of type parameters.

class ChainedMap<K1..., V>

Another option would be to have a ChainedMapUtil class that performs put / get recursively.

Here is an example of a recursive get. (Quite ugly solution though I must say.)

import java.util.*;

public class Test {

    public static Object chainedGet(Map<?, ?> map, Object... keys) {

        Object k = keys[0];

        if (!map.containsKey(k)) return null;

        if (keys.length == 1) return map.get(k);

        Object[] tailKeys = Arrays.copyOfRange(keys, 1, keys.length);
        return chainedGet((Map<?,?>) map.get(k), tailKeys);        
    }

    public static void main(String[] arg) {

        Map<String, String> m1 = new HashMap<String, String>();
        m1.put("ipsum", "dolor");

        Map<Integer, Map<String, String>> m2 =
                new HashMap<Integer, Map<String, String>>();
        m2.put(17, m1);

        Map<String, Map<Integer, Map<String, String>>> chained =
            new HashMap<String, Map<Integer, Map<String, String>>>();
        chained.put("lorem", m2);

        System.out.println(chainedGet(chained, "lorem", 17, "ipsum")); // dolor
        System.out.println(chainedGet(chained, "lorem", 19, "ipsum")); // null
    }
}
单身情人 2024-10-15 06:08:04

如果您要编写自己的键,我建议

eaten.increment(me, evening, scrambledEggs);

您可以使用复合键

eaten.increment(Key.of(me, evening, scrambledEggs));

(TObjectIntHashMap 支持增量和调整)

您甚至可能不需要自定义键。

eaten.increment(me + "," + evening + "," + scrambledEggs);

使用 split() 分解密钥相当容易

If you are going to write your own, I would suggest

eaten.increment(me, evening, scrambledEggs);

You could use a composite key

eaten.increment(Key.of(me, evening, scrambledEggs));

(TObjectIntHashMap supports increment and adjust)

You may not even need a custom key.

eaten.increment(me + "," + evening + "," + scrambledEggs);

It is fairly easy to decompose the key with split()

蓝眸 2024-10-15 06:08:04

我曾经使用 3 个键制作了一个地图只是为了好玩。也许你可以使用它而不是使用链式地图:

public class ThreeKeyMap<K1,K2,K3,V>{

class wrap{
    K1 k1;
    K2 k2;
    K3 k3;
    public wrap(K1 k1,K2 k2,K3 k3) {
        this.k1=k1;this.k2=k2;this.k3=k3;
    }
    @Override
    public boolean equals(Object arg0) {
        // TODO Auto-generated method stub
        wrap o=(wrap)arg0;
    if(!this.k1.equals(o.k1))
        return false;
    if(!this.k2.equals(o.k2))
        return false;
    if(!this.k2.equals(o.k2))
        return false;
    return true;

    }
    @Override
    public int hashCode() {
        int result=17;
        result=37*result+k1.hashCode();
        result=37*result+k2.hashCode();
        result=37*result+k3.hashCode();
        return result;
    }
}
HashMap<wrap,V> map=new HashMap<wrap, V>();

public V put(K1 k1,K2 k2,K3 k3,V arg1) {
    return map.put(new wrap(k1,k2,k3), arg1);
}


public V get(Object k1,Object k2,Object k3) {
    return map.get(new wrap((K1)k1,(K2)k2,(K3)k3));
}

public static void main(String[] args) {
    ThreeKeyMap<Integer,Integer,Integer,String> birthDay=new ThreeKeyMap<Integer, Integer, Integer, String>();
    birthDay.put(1, 1,1986,"Emil");
    birthDay.put(2,4,2009, "Ansih");
    birthDay.put(1, 1,1986,"Praveen");
    System.out.println(birthDay.get(1,1,1986));
}
}

更新:

正如 @Arturs Licis 所建议的。我在网上查找了复合模式,然后写了使用它的示例。我猜这是复合的。如果不是这样,请发表评论。

人物类别:

public class Person {
    private final String name;
    private Map<Time, Food> map = new HashMap<Time, Food>();

    public Person(String name) {
        this.name = name;
    }

    void addTimeFood(Time time, Food food) {
        map.put(time, food);
    }

    public String getName() {
        return name;
    }

    Food getFood(Time time) {
        Food tmp = null;
        return (tmp = map.get(time)) == null ? Food.NoFood : tmp;
    }
    // main to test the person class
    public static void main(String[] args) { 
        Person p1 = new Person("Jack");
        p1.addTimeFood(Time.morning, Food.Bread);
        p1.addTimeFood(Time.evening, Food.Chicken);

        Person p2 = new Person("Jill");
        p2.addTimeFood(Time.morning, Food.Egg);
        p2.addTimeFood(Time.evening, Food.Rice);

        Map<String, Person> map = new HashMap<String, Person>();
        map.put(p1.getName(), p1);
        map.put(p2.getName(), p2);
        System.out.println(map.get("Jack").getFood(Time.evening));
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder();
        b.append(name).append("\n");
        b.append(map);
        return b.toString();
    }
}

食物类别:

public enum Food {
Rice,
Egg,
Chicken,
Bread,
NoFood;
}

时间类别:

public enum Time {
morning,
evening,
night
}

I once made a map using 3 keys just for fun.May be you can use it instead of using chained maps:

public class ThreeKeyMap<K1,K2,K3,V>{

class wrap{
    K1 k1;
    K2 k2;
    K3 k3;
    public wrap(K1 k1,K2 k2,K3 k3) {
        this.k1=k1;this.k2=k2;this.k3=k3;
    }
    @Override
    public boolean equals(Object arg0) {
        // TODO Auto-generated method stub
        wrap o=(wrap)arg0;
    if(!this.k1.equals(o.k1))
        return false;
    if(!this.k2.equals(o.k2))
        return false;
    if(!this.k2.equals(o.k2))
        return false;
    return true;

    }
    @Override
    public int hashCode() {
        int result=17;
        result=37*result+k1.hashCode();
        result=37*result+k2.hashCode();
        result=37*result+k3.hashCode();
        return result;
    }
}
HashMap<wrap,V> map=new HashMap<wrap, V>();

public V put(K1 k1,K2 k2,K3 k3,V arg1) {
    return map.put(new wrap(k1,k2,k3), arg1);
}


public V get(Object k1,Object k2,Object k3) {
    return map.get(new wrap((K1)k1,(K2)k2,(K3)k3));
}

public static void main(String[] args) {
    ThreeKeyMap<Integer,Integer,Integer,String> birthDay=new ThreeKeyMap<Integer, Integer, Integer, String>();
    birthDay.put(1, 1,1986,"Emil");
    birthDay.put(2,4,2009, "Ansih");
    birthDay.put(1, 1,1986,"Praveen");
    System.out.println(birthDay.get(1,1,1986));
}
}

UPDATE:

As @Arturs Licis suggested.I looked up in net for composite pattern and I wrote a sample using it.I guess this is composite..Please comment if it is not so.

Person class:

public class Person {
    private final String name;
    private Map<Time, Food> map = new HashMap<Time, Food>();

    public Person(String name) {
        this.name = name;
    }

    void addTimeFood(Time time, Food food) {
        map.put(time, food);
    }

    public String getName() {
        return name;
    }

    Food getFood(Time time) {
        Food tmp = null;
        return (tmp = map.get(time)) == null ? Food.NoFood : tmp;
    }
    // main to test the person class
    public static void main(String[] args) { 
        Person p1 = new Person("Jack");
        p1.addTimeFood(Time.morning, Food.Bread);
        p1.addTimeFood(Time.evening, Food.Chicken);

        Person p2 = new Person("Jill");
        p2.addTimeFood(Time.morning, Food.Egg);
        p2.addTimeFood(Time.evening, Food.Rice);

        Map<String, Person> map = new HashMap<String, Person>();
        map.put(p1.getName(), p1);
        map.put(p2.getName(), p2);
        System.out.println(map.get("Jack").getFood(Time.evening));
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder();
        b.append(name).append("\n");
        b.append(map);
        return b.toString();
    }
}

Food class:

public enum Food {
Rice,
Egg,
Chicken,
Bread,
NoFood;
}

Time class:

public enum Time {
morning,
evening,
night
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文