![](/img/trans.png)
[英]How to display flat data structure into hierarchical data structure (Java)?
[英]Java - Read Hierarchical data from flat structure in text file and build hashmap
我有一個文本文件,該文本文件中的分層結構中的分層數據可用。
child parent
Y, X
Z, Y
A, Z
就像X是Y的父級,Y本身是Z的父級,Z又是A的父級。它可以按任何順序出現在文件中。 我需要構建一個哈希圖,其中鍵應該是元素,值應該是所有祖先元素的列表。 例如,哈希圖應具有基於上述數據的條目,例如
A = [Z,Y,X],Y = [X],Z = [Y,X]。
我已經在Java中編寫了代碼來構建此哈希圖。 只需要知道是否有更有效的方法可以做到這一點。 邏輯是
從上面創建的哈希圖中,遞歸遍歷每個孩子並建立父母列表。
public class Test { public static final String FILE_NAME = "dataset1"; public static final HashMap<String,String> inputMap = new HashMap<String,String>(); public static final Map<String, ArrayList<String>> parentChildMap = new HashMap<String,ArrayList<String>>(); private static void readTextFile(String aFileName) throws IOException { Path path = Paths.get(aFileName); try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)){ String line = null; while ((line = reader.readLine()) != null) { String[] dataArray = line.split(","); String child = dataArray[0]; String parent = dataArray[1]; inputMap.put(child, parent); } } } public static ArrayList<String> getParents(String childId, ArrayList<String> parents) { if (childId == null) return parents; String parentId = inputMap.get(childId); if(parentId!=null) parents.add(parentId); getParents(parentId, parents); return parents; } public static void main(String[] s) throws IOException { readTextFile(FILE_NAME); for(String child : inputMap.keySet()) { ArrayList<String> parents = getParents(child, new ArrayList<String>()); parentChildMap.put(child, parents); } }
遞歸已經非常有效。 您可以優化以下內容:
這是我的代碼:
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static final String FILE_NAME = "dataset1";
public static final HashMap<String, String> inputMap = new HashMap<String, String>();
public static final Map<String, ArrayList<String>> parentChildMap = new HashMap<String, ArrayList<String>>();
private static void readTextFile(String aFileName) throws IOException {
Path path = Paths.get(aFileName);
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
String line = null;
while ((line = reader.readLine()) != null) {
String[] dataArray = line.split(",");
String child = dataArray[0];
String parent = dataArray[1];
inputMap.put(child, parent);
}
}
// this replaces the recursion:
for (String k : inputMap.keySet()) {
String ok = k;
ArrayList<String> tmp = new ArrayList<String>();
while (true) {
// if this has already been computed, use old answer
if (parentChildMap.containsKey(k)) {
tmp.addAll(parentChildMap.get(k));
break;
}
if (inputMap.containsKey(k)) {
String v = inputMap.get(k);
tmp.add(v);
k = v;
} else {
break;
}
}
parentChildMap.put(ok, tmp);
}
}
public static ArrayList<String> getParents(String childId) {
// do not recompute
return parentChildMap.get(childId);
}
}
您要的是“更有效的方法”,所以這是我的批評(次要)和建議。
line
初始化為null
。 只是聲明它。 split()
。 它可能會拆分為兩個以上的值,並且必須創建一個數組。 只需使用indexOf()
。 因此,第一種方法變為(壓縮一些):
public static final Map<String, String> inputMap = new HashMap<>();
private static void readTextFile(String aFileName) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(Paths.get(aFileName),
StandardCharsets.UTF_8)){
for (String line; (line = reader.readLine()) != null; ) {
int idx = line.indexOf(',');
inputMap.put(/*child*/line.substring(0, idx),
/*parent*/line.substring(idx + 1));
}
}
}
現在提出建議。
您的代碼多次解析相同的父級,例如,檢索A
父級時,它必須遍歷整個父鏈Z
, Y
, X
,而檢索Z
的父級時,則必須遍歷父鏈Y
, X
。 您多次進行相同的步行。
只執行一次會更有效。 由於數據是無序的,因此必須使用遞歸進行處理。 我已經將parentChildMap
重命名為一個更合適的ancestorMap
。
public static final Map<String, List<String>> ancestorMap = new HashMap<>();
private static List<String> getAncestors(String child) {
// Check if ancestors already resolved
List<String> ancestors = ancestorMap.get(child);
if (ancestors == null) {
// Find parent
String parent = inputMap.get(child);
if (parent == null) {
// Child has no parent, i.e. no ancestors
ancestors = Collections.emptyList();
} else {
// Find ancestors of parent using recursive call
List<String> parentAncestors = getAncestors(parent);
if (parentAncestors.isEmpty()) {
// Parent has no ancestors, i.e. child has single ancestor (the parent)
ancestors = Collections.singletonList(parent);
} else {
// Child's ancestors is parent + parentAncestors
ancestors = new ArrayList<>(parentAncestors.size() + 1);
ancestors.add(parent);
ancestors.addAll(parentAncestors);
}
}
// Save resolved ancestors
ancestorMap.put(child, ancestors);
}
return ancestors;
}
如果您不關心使用emptyList()
和singletonList()
的優化或有注釋,可以將其壓縮為:
private static List<String> getAncestors(String child) {
List<String> ancestors = ancestorMap.get(child);
if (ancestors == null) {
ancestorMap.put(child, ancestors = new ArrayList<>());
String parent = inputMap.get(child);
if (parent != null) {
ancestors.add(parent);
ancestors.addAll(getAncestors(parent));
}
}
return ancestors;
}
然后, main
方法變為:
public static final String FILE_NAME = "dataset1";
public static void main(String[] args) throws IOException {
readTextFile(FILE_NAME);
for (String child : inputMap.keySet())
getAncestors(child); // Ignore return value
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.