首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >映射映射的Java映射重构

映射映射的Java映射重构
EN

Stack Overflow用户
提问于 2016-03-27 07:07:40
回答 6查看 5.6K关注 0票数 6

我正在查看一个项目的旧代码,并使用Map of Map of Map(3层地图)获得如下数据结构:

代码语言:javascript
运行
复制
// data structure
Map<String, Map<String, Map<String, List<String>>>> tagTree 
            = new HashMap<String, Map<String,Map<String,List<String>>>>();

并从Map中获取值(我认为这是很好的部分)

代码语言:javascript
运行
复制
// fetch at tag values
List<String> tagList1 = tagTree.get("Java").get("Active").get("Tags");
List<String> tagList2 = tagTree.get("Java").get("Latest").get("SubTags");

将值放在Map中(有点复杂且容易出错)

代码语言:javascript
运行
复制
// put values
Map<String, Map<String, List<String>>> javaLangMap = new HashMap<String, Map<String, List<String>>>();
Map<String, List<String>> javaStatusMap = new HashMap<String, List<String>>();
List<String> javaTagList = new ArrayList<String>();

javaTagList.add("Java-OOP");
javaTagList.add("Java-Variables");
// put tag list
javaStatusMap.put("Tags", javaTagList);
// put status-wise tag
javaLangMap.put("Active", javaStatusMap);
// put language-wise tag
tagTree.put("Java", javaLangMap);

目前,这将用于维护以下结构

TagLanguage -> TagStatus -> TagType -> TagList

我计划重构这个地图,因为对其他开发人员来说它很难理解。

请分享你的想法,如何通过考虑以下情况:

  • 所有四个层都可以在运行时进行更改。
  • 所有级别都可以访问
  • 内存中所需的解决方案,即不使用数据库表层次结构。
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2016-03-27 08:35:57

如果您只想访问数据结构的最后一个级别,则可以使用Multimap<Triple<String,String,String>,String>Multimap是一个来自番石榴的数据结构,基本上是一个更好的Map<K,Collection<V>>Triple是Apache的三元素元组数据结构,TripleComparable,实现了equals

您可以这样声明标记树:

代码语言:javascript
运行
复制
Multimap<Triple<String, String, String>, String> tagTree = HashMultimap.create();

然后把它填成这样:

代码语言:javascript
运行
复制
tagTree.put(Triple.of("Java", "Active", "Tags"), "Java-OOP");
tagTree.put(Triple.of("Java", "Active", "Tags"), "Java-Variables");

或者:

代码语言:javascript
运行
复制
tagTree.putAll(Triple.of("Java", "Active", "Tags"), Arrays.asList("Java-OOP", "Java-Variables"));

然后像这样得到你的价值观:

代码语言:javascript
运行
复制
Set<String> values = tagTree.get(Triple.of("Java", "Active", "Tags"));

下面是另一个适合您的粗略解决方案,可以使用1、2或3键获得:

代码语言:javascript
运行
复制
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

public class ThreeLevelMap<K1, K2, K3, V> {
    private Map<K1, Map<K2, Multimap<K3, V>>> firstLevelMap = new HashMap<>();
    private Map<Pair<K1, K2>, Multimap<K3, V>> secondLevelMap = new HashMap<>();
    private Multimap<Triple<K1, K2, K3>, V> thirdLevelMap = HashMultimap.create();

    public void put(K1 key1, K2 key2, K3 key3, V value) {
        thirdLevelMap.put(Triple.of(key1, key2, key3), value);

        final Pair<K1, K2> secondLevelKey = Pair.of(key1, key2);
        Multimap<K3, V> secondLevelContainer = secondLevelMap.get(secondLevelKey);
        if (secondLevelContainer == null) {
            secondLevelContainer = HashMultimap.create();
            secondLevelMap.put(secondLevelKey, secondLevelContainer);
        }
        secondLevelContainer.put(key3, value);

        Map<K2, Multimap<K3, V>> firstLevelContainer = firstLevelMap.get(key1);
        if (firstLevelContainer == null) {
            firstLevelContainer = new HashMap<>();
            firstLevelMap.put(key1, firstLevelContainer);
        }
        firstLevelContainer.put(key2, secondLevelContainer);
    }

    public Collection<V> get(K1 key1, K2 key2, K3 key3) {
        return thirdLevelMap.get(Triple.of(key1, key2, key3));
    }

    public Multimap<K3, V> get(K1 key1, K2 key2) {
        return secondLevelMap.get(Pair.of(key1, key2));
    }

    public Map<K2, Multimap<K3, V>> get(K1 key1) {
        return firstLevelMap.get(key1);
    }
}

你可以这样使用它:

代码语言:javascript
运行
复制
ThreeLevelMap<String, String, String, String> tlm = new ThreeLevelMap<>();
tlm.put("Java", "Active", "Tags", "Java-OOP");
tlm.put("Java", "Active", "Tags", "Java-Variables");

Map<String, Multimap<String, String>> firstLevelMap = tlm.get("Java");
Multimap<String, String> secondLevelMap = tlm.get("Java", "Active");
Collection<String> tags = tlm.get("Java", "Active", "Tags");

我说这很难,因为:

  • get方法返回的映射是可修改的。
  • 我没有实现remove方法
  • 我没做太多测试
票数 11
EN

Stack Overflow用户

发布于 2016-03-27 07:15:40

您可以创建包含数据结构的类。

代码语言:javascript
运行
复制
public class A {
    Map<String, List<String>> map;
}

public class B {
    Map<String, A> map;
}

Map<String, B> tagTree;
票数 2
EN

Stack Overflow用户

发布于 2016-03-27 07:22:18

我不认为这是一个如此糟糕的解决方案。这只是一种树的表示法,对于每一片叶子都在3级的树来说。如果不是这样的话(不同的叶子级别,等等)。您必须建立一个树类结构。

但我要更改的是将所有内容放入一个中,其中包含一个get和set方法,包括null-checks

在下面的代码中,add方法负责处理容易出错的中间级别映射,而get在中间级别检查空值:

代码语言:javascript
运行
复制
public class TreeStructure {
  Map<String, Map<String, Map<String, List<String>>>> tagTree 
            = new HashMap<String, Map<String,Map<String,List<String>>>>();

  // ... Constructor ...

  // This method adds all intermediate levels if not existing
  public void add(String level1, String level2, String level3) {
    String l1 = tagTree.get(level1);
    if(l1 == null)
      tagTree.put(level1, new HashMap<String, Map<String, List<String>>>());
    l1 = tagTree.get(level1);
    String l2 = l1.get(level2),
    if(l2 == null)
      tagTree.put(level2, new Map<String, List<String>>(););
    l2 = l1.get(level2);
    String l3 = l2.get(level3);
    if(l3 == null) l2.add(level3, new ArrayList<>());
  }

  // This method checks, if every intermediate level existed
  // Otherwise, get() returns null, and the next get() would fail
  public String get(String level1, String level2, String level3) {
    String l1 = tagTree.get(level1);
    if(l1 == null)
      return null;
    String l2 = l1.get(level2),
    if(l2 == null)
      return null;
    l2 = l1.get(level2);
    String l3 = l2.get(level3);
    return l3;
  }
}

(未经测试的代码)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36244782

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档