В настоящее время я работаю над инструментом распаковки для майнкрафта и получил аккуратный рабочий результат, который показывает все материалы, необходимые в дереве. Интересно, можно ли как-то улучшить код, используемый для печати этого дерева. У меня есть только глубина рекурсии как измерение, а ArrayList
заполняется в том же порядке, что и в примере ввода ниже. Формат вывода также должен остаться прежним, меня это вполне устраивает. Формат ввода немного схематичен, любые идеи по этому поводу также приветствуются.
Алгоритм
private static void treeprint(ArrayList<Object[]> tree) {
ArrayList<String> stem = new ArrayList<>();
for (int i = 0; i < tree.size() - 1; i++) {
System.out.print(String.join("", stem));
Object[] o = tree.get(i);
int cdepth = (int) o[0];
String cname = (String) o[1];
int camt = (int) o[2];
int ndepth = (int) tree.get(i + 1)[0];
if (ndepth > cdepth) {
if (isLastOfDepth(tree, cdepth, i + 1)) {
System.out.print("\---");
stem.add(" ");
} else {
System.out.print("+---");
stem.add("| ");
}
}
if (ndepth == cdepth) {
if (isLastOfDepth(tree, cdepth, i + 1)) {
System.out.print("\---");
} else {
System.out.print("+---");
}
}
if (ndepth < cdepth) {
System.out.print("\---");
for (int j = 0; j < cdepth - ndepth; j++) {
stem.remove(stem.size() - 1);
}
}
System.out.println(cname + " x " + camt);
}
System.out.println(String.join("", stem) + "\---" + (String) tree.get(tree.size() - 1)[1] + " x "
+ (int) tree.get(tree.size() - 1)[2]);
}
private static boolean isLastOfDepth(ArrayList<Object[]> tree, int depth, int start) {
for (int i = start; i < tree.size(); i++) {
int cdepth = (int) tree.get(i)[0];
if (cdepth < depth) {
return true;
}
if (cdepth == depth) {
return false;
}
}
return true;
}
Тестовый ввод
Формат: глубина рекурсии / название предмета / количество предмета
1 component heat vent 1
2 iron bars 4
3 iron 6
2 heat vent 1
3 electric motor 1
4 coil 2
5 copper cable 8
5 iron 1
4 iron 1
4 tin item casing 2
3 iron bars 4
4 iron 6
3 iron plate 4
2 tin plate 4
1 ответ
Хорошее решение, мои предложения:
Короткие имена переменных: переменные типа
camt
иcname
может быть расширен доcurrentAmount
иcurrentName
. Для удобства чтения лучше иметь более длинные имена. Например, я не уверен, чтоstem
означает.Типы и проверка ввода: в методах много приведений, которые не прошли валидацию. Принятие массива
Object
без всякой проверки — рецепт неприятностей. Используя класс, вы можете решить обе проблемы, примерно так:class Node{ private int depth; private String itemName; private int amount; public Node(int depth, String itemName, int amount) { // Input validation here this.depth = depth; this.itemName = itemName; this.amount = amount; } // Getters, etc. }
Итак, этот код:
Object[] o = tree.get(i); int cdepth = (int) o[0]; String cname = (String) o[1]; int camt = (int) o[2];
Может стать:
Node node = tree.get(i); int currentDepth = node.getDepth(); String currentItemName = node.getItemName(); int currentAmount = node.getAmount();
Вы также можете сделать свойства класса
final
иметь неизменяемый узел.Константы: струны
---
и+---
повторяются несколько раз. Подумайте о создании констант для таких специальных строк, чтобы их было легче изменить в будущем.Функциональность: Если список составлен неправильно, дерево не будет напечатано правильно. Например: ввод:
1 a 1 2 b 1 3 c 1 4 d 1
Производит правильный вывод:
---a x 1 ---b x 1 ---c x 1 ---d x 1
Но если мы добавим еще один узел посередине:
1 a 1 2 b 1 3 c 1 2 e 1 4 d 1
Результат становится:
---a x 1 +---b x 1 | ---c x 1 ---e x 1 ---d x 1
Сейчас же
d
изменил свою глубину с4
к3
иe
стал его отцом.Если дерево растет в размерах, создание правильно сформированного списка узлов соответствующей глубины — непростая задача. Решением может быть создание
Tree
класс, который знает, как добавлять и удалять узлы. ЗатемtreePrint
метод сделает Предварительный заказ сканировать дерево и распечатывать узлы в пути.