我正在审核项目的旧代码,并使用The following cache components were processed:
* cache (yii\\caching\\FileCache)
Map
Map
(3层地图)的Map
获得了数据结构:
// data structure
Map<String, Map<String, Map<String, List<String>>>> tagTree
= new HashMap<String, Map<String,Map<String,List<String>>>>();
从Map中获取值(我认为这是很好的部分)
// 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中(有点复杂且容易出错)
// 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 - &gt; TagStatus - &gt; TagType - &gt;标记表
我计划重构此地图,因为其他开发者很难阅读。
请分享您的想法如何通过考虑以下案例来做到这一点:
答案 0 :(得分:11)
如果您只想访问数据结构的最后一级,可以使用(d % 1) == 0
。 Multimap<K,V>
是来自Guava的数据结构,基本上是一个更好的Multimap<Triple<String,String,String>,String>
。 Triple<L,M,R>
是来自Apache Commons Lang3的3元素元组数据结构,Map<K,Collection<V>>
并实现Comparable
。
你可以像这样声明你的标签树:
equals
然后像这样填写:
Multimap<Triple<String, String, String>, String> tagTree = HashMultimap.create();
或者:
tagTree.put(Triple.of("Java", "Active", "Tags"), "Java-OOP");
tagTree.put(Triple.of("Java", "Active", "Tags"), "Java-Variables");
然后从中获取您的价值:
tagTree.putAll(Triple.of("Java", "Active", "Tags"), Arrays.asList("Java-OOP", "Java-Variables"));
这是另一个可能适合您的粗略解决方案,可以使用1,2或3个键:
Set<String> values = tagTree.get(Triple.of("Java", "Active", "Tags"));
你可以这样使用它:
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);
}
}
我说这很粗糙,因为:
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
方法答案 1 :(得分:2)
您可以创建将保存数据结构的类
public class A {
Map<String, List<String>> map;
}
public class B {
Map<String, A> map;
}
Map<String, B> tagTree;
答案 2 :(得分:2)
我认为这不是一个糟糕的解决方案。 它只是一个树表示,对于每棵叶子都在3级的树。 如果不是这种情况(不同的叶级别等),则必须构建树类结构。
但我要改变的是将所有内容放在类中,并使用get和set方法,包括 null-checks 。
在下面的代码中,add
方法处理中间级别映射的容易出错的处理,而get
检查中间级别的空值:
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;
}
}
(未经测试的代码)
答案 3 :(得分:2)
使用3元组的地图:
class Tuple3<A,B,C> {
private A a;
private B b;
private C c;
// getters, setters, constructor
// make sure equals() and hashCode() are okay
}
但请注意,地图的地图可以通过查看外部地图在O(1)中告诉您是否有某些元素的条目。然而,使用元组解决方案,您只能使用完整密钥。
答案 4 :(得分:1)
我认为没有理由重构这个Map
结构。但是如果可能的话,将这个Map
封装在另一个class
中并为其他开发人员提供一个干净的界面可能是个好主意。
...
public void addTag(String language, String status, String tag)
public void removeTag(String language, String status, String tag)
public List<String> getTags(String language, String status)
...
答案 5 :(得分:1)
我喜欢上面提到的大多数解决方案。我认为设计更简单有效 - 它将更加可支持。
因此,我使用基础知识 - 普通对象组合来重构代码。
package design;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class JavaTag{
private String tags;
JavaTag(String tags){
this.tags = tags;
}
}
class JavaTagStatusList{
private ArrayList<JavaTag> tagList = new ArrayList<JavaTag>();
JavaTagStatusList(){
}
public void addJavaTag (JavaTag tagObj){
if (tagObj != null){
tagList.add(tagObj);
}
}
}
class JavaTagStatusMap {
private HashMap<String, JavaTagStatusList> tagStatusMap = new HashMap<String, JavaTagStatusList>();
JavaTagStatusMap(){
}
public void addTagStatusEntry(String status, JavaTag obj){
if (tagStatusMap.containsKey(status)){
tagStatusMap.get(status).addJavaTag(obj);
}
else {
JavaTagStatusList statusList = new JavaTagStatusList();
statusList.addJavaTag(obj);
tagStatusMap.put(status, statusList);
}
}
}
主:
public class MapofMapRefactor {
public static void main(String[] args) {
JavaTag tag1 = new JavaTag("Java-OOP");
JavaTag tag2 = new JavaTag("Java-Variables");
JavaTagStatusMap statusMap = new JavaTagStatusMap();
statusMap.addTagStatusEntry("Active", tag1);
statusMap.addTagStatusEntry("Active", tag2);
// HashMap of Java Lang Map
HashMap<String, JavaTagStatusMap> javaLanguageMap = new HashMap<String, JavaTagStatusMap>();
javaLanguageMap.put("Java", statusMap);
}
}