I have a program that saves/loads data to a text file. However, some data seems to not be saving, and I can't figure out why.
Here's a simplified version of the code.
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
public class Test {
private static DumperOptions options;
private static File saveLocation;
private static Map<String, Object> data;
private static Representer representer;
private static String path;
private static Yaml yaml;
private static void setup() {
saveLocation = new File(path);
if (!saveLocation.exists())
try {
saveLocation.createNewFile();
} catch (IOException exception) {
exception.printStackTrace();
}
setupDumper();
yaml = new Yaml(representer, options);
data = Collections.synchronizedMap(new LinkedHashMap<String, Object>());
}
private static void setupDumper() {
options = new DumperOptions();
representer = new Representer();
options.setIndent(2);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setAllowUnicode(Charset.defaultCharset().name().contains("UTF"));
representer.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
}
public static boolean contains(String key) {
return data.containsKey(key);
}
public static boolean exists() {
return data != null;
}
public static boolean hasValue(String key) {
Object tempObject = data.get(key);
return (tempObject != null);
}
public static boolean isEmpty() {
return data.isEmpty() || data == null;
}
public static int getInteger(String key) {
Object tempObject = get(key);
if (tempObject instanceof Integer)
return (Integer) tempObject;
if (tempObject instanceof String)
return Integer.parseInt(tempObject.toString());
if (tempObject instanceof Number)
return Integer.parseInt(tempObject.toString());
return -1;
}
public static Object get(String key) {
if (isEmpty())
return null;
if (key.contains(".")) {
String[] nodes = key.split("\\.");
Map<String, Object> currParent;
if (data.containsKey(nodes[0]) && (data.get(nodes[0]) instanceof Map))
currParent = (Map) data.get(nodes[0]);
else return null;
if (nodes.length > 1) {
for (int i = 1; i < nodes.length - 1; i++) {
if (currParent.containsKey(nodes[i]) && (currParent.get(nodes[i]) instanceof Map))
currParent = (Map) currParent.get(nodes[i]);
else return null;
}
if (currParent.containsKey(nodes[nodes.length - 1]))
return currParent.get(nodes[nodes.length - 1]);
}
} else if (!contains(key) || (contains(key) && !hasValue(key)))
return null;
return data.get(key);
}
public static FileReader read(File file) {
try {
if (!file.exists())
return null;
return new FileReader(file);
} catch (FileNotFoundException exception) {
exception.printStackTrace();
}
return null;
}
public static boolean load() {
setup();
FileReader reader = read(saveLocation);
if (reader == null) {
data = Collections.synchronizedMap(new LinkedHashMap<String, Object>());
return true;
}
data = Collections.synchronizedMap((Map<String, Object>) yaml.load(reader));
System.out.println(getInteger("Settings.Difficulty.Level"));
System.out.println(getInteger("Settings.Difficulty.Locked"));
System.out.println(getInteger("Settings.Cheats.Enabled"));
System.out.println(getInteger("Settings.Cheats.Locked"));
System.out.println(getInteger("Settings.GUI.Enabled"));
System.out.println(data.toString());
return true;
}
public static void save() {
//Settings
set("Settings.Difficulty.Level", 1);// not saving
set("Settings.Difficulty.Locked", 2);
set("Settings.Cheats.Enabled", 3); // not saving
set("Settings.Cheats.Locked", 4);
set("Settings.GUI.Enabled", 5);
try {
if (!saveLocation.exists())
saveLocation.createNewFile();
FileWriter writer = new FileWriter(saveLocation);
writer.write(yaml.dump(data));
writer.flush();
writer.close();
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void set(String key, Object object) {
if (!exists())
return;
if (key.contains(".")) {
String[] nodes = key.split("\\.");
// if data doesn't contain top-level node, create nested Maps
if (!data.containsKey(nodes[0])) {
Map<String, Object> currNode = new HashMap<>(), prevNode;
currNode.put(nodes[nodes.length - 1], object);
for (int i = nodes.length - 2; i > 0; i--) {
prevNode = currNode;
currNode = new HashMap<>();
currNode.put(nodes[i], prevNode);
}
// set top-level node to previous parent
data.put(nodes[0], currNode);
} else { // if data contains top-level node, work through each Map
Map[] prevNodes = new LinkedHashMap[nodes.length - 1];
if (nodes.length > 1) {
for (int i = 0; i <= nodes.length - 2; i++) {
if (data.containsKey(nodes[i]) && (data.get(nodes[i]) instanceof Map))
prevNodes[i] = new LinkedHashMap((Map) data.get(nodes[i]));
else if (!data.containsKey(nodes[i]))
prevNodes[i] = new LinkedHashMap();
}
prevNodes[prevNodes.length - 1].put(nodes[nodes.length - 1], object);
for (int i = prevNodes.length - 1; i >= 1; i--)
prevNodes[i - 1].put(nodes[i], prevNodes[i]);
data.put(nodes[0], prevNodes[0]);
} else data.put(nodes[0], object);
}
return;
}
data.put(key, object);
}
public static void main(String[] args) {
path = "test.txt";
setup();
save();
load();
}
}
Normally it'll save integers from a bunch of other classes, then when the program is run again, loads it back into the appropriate variables. But for the sake of testing, all it does is print out the values.
//Settings
set("Settings.Difficulty.Level", 1);// not saving
set("Settings.Difficulty.Locked", 2);
set("Settings.Cheats.Enabled", 3); // not saving
set("Settings.Cheats.Locked", 4);
set("Settings.GUI.Enabled", 5);
This should save integers (1 to 5) to test.txt, and then prints them to the console
System.out.println(getInteger("Settings.Difficulty.Level"));
System.out.println(getInteger("Settings.Difficulty.Locked"));
System.out.println(getInteger("Settings.Cheats.Enabled"));
System.out.println(getInteger("Settings.Cheats.Locked"));
System.out.println(getInteger("Settings.GUI.Enabled"));
When I run the file, I expect to get the output of
1
2
3
4
5
But I actually get
-1
2
-1
4
5
Settings.Difficulty.Level and Settings.Cheats.Enabled doesnt even seem to be saved in the file at all.
Settings:
Difficulty:
Locked: 2
Cheats:
Locked: 4
GUI:
Enabled: 5
I'm pretty sure the issue is somewhere in the set method, but I'm not sure exactly what it is. I also don't know why its only two of the 5 variables that won't save (Must be something to do with the name used).
The error is here:
for (int i = 0; i <= nodes.length - 2; i++) {
if (data.containsKey(nodes[i]) && (data.get(nodes[i]) instanceof Map))
prevNodes[i] = new LinkedHashMap((Map) data.get(nodes[i]));
else if (!data.containsKey(nodes[i]))
prevNodes[i] = new LinkedHashMap();
}
This code is executed with the second set call. It finds "Settings" in data, but then, it does not find "Difficulty" in data (because that is in the "Settings" map). So it creates a new, empty LinkedHashMap. Then, this code happens:
prevNodes[prevNodes.length - 1].put(nodes[nodes.length - 1], object);
for (int i = prevNodes.length - 1; i >= 1; i--)
prevNodes[i - 1].put(nodes[i], prevNodes[i]);
It replaces the existing "Difficulty" node (which contains "Level") with the newly created one (which contains only "Locked"). Thus, "Level" is missing afterwards.
You can modify your for loop like this:
for (int i = 0; i <= nodes.length - 2; i++) {
final Map cur = (i == 0) ? data : prevNodes[i - 1];
if (cur.containsKey(nodes[i]) && (cur.get(nodes[i]) instanceof Map))
prevNodes[i] = new LinkedHashMap((Map) cur.get(nodes[i]));
else if (!cur.containsKey(nodes[i]))
prevNodes[i] = new LinkedHashMap();
}
But actually, the whole set method can be simplified: (Beware, this is untested code and may contain minor errors)
public static void set(String key, Object object) {
if (!exists())
return;
// no need to differentiate between paths with and without "."
final String[] nodes = key.split("\\.");
Map cur = data;
for (int i = 0; i <= nodes.length - 2; ++i) {
Object val = cur.get(nodes[i]);
if (val == null) {
val = new LinkedHashMap();
cur.put(nodes[i], val);
} else if (!(val instanceof Map)) {
// error in structure, handle it here (throw exception, …)
}
cur = (Map) val;
}
cur.put(nodes[nodes.length - 1], object);
}
Related
I am trying to create a class called HybridTST, where I can add multiple different TST's to a bigger data structure.
I have tried creating an array of Ternary Search Trees to a letter in the alphabet and then when I want to go to a specific TST I can iterate through the alphabet to find the correct TST. I am not sure if that the outcome is what I want. Am I creating a this Hybrid TST incorrectly?
public class HybridTST<E> implements TrieInterface
{
private TST[] myHybridTST = new TST[54];
private String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.'";
private int position = 0;
private int size;
HybridTST()
{
char[] alphabetArray = alphabet.toCharArray();
for (int i = 0; i<54; i++)
{
myHybridTST[i]= new TST(alphabetArray[i]);
}
}
#Override
public Object get(String key) {
if (key == null) {
throw new InvalidKeyException();
}
for (int i = 0; i < key.length(); i++) {
if (!Character.isLetter(key.charAt(i))) {
throw new InvalidKeyException();
}
}
position = 0;
for(char c: alphabet.toCharArray())
{
if(key.charAt(0)==c)
{
break;
}
position++;
}
return myHybridTST[position].get(key);
}
Here is the TST get portion:
public Object get(String key) {
if (key == null) {
throw new InvalidKeyException();
}
if (key == null)
throw new NullPointerException();
if(key!="aren't")
{
for (int i = 0; i < key.length(); i++) {
if (!Character.isLetter(key.charAt(i))) {
throw new InvalidKeyException();
}
}
}
Node x = get(root, key, 0);
if (x == null) return null;
return x.val;
}
private Node get(Node x, String key, int d) {
if (key == null) {
throw new InvalidKeyException();
}
if (key.length() == 0)
throw new IllegalArgumentException("key must have length >= 1");
if (x == null)
return null;
char c = key.charAt(d);
if (c<x.c)
{
return get(x.left, key, d);
}
else if(c>x.c)
{
return get(x.right, key, d);
}
else if(d < key.length()-1)
{
return get(x.mid, key, d+1);
}
else
{
return x;
}
}
Here is the test:
public void test10()
{
HybridTST<Integer> t = new HybridTST<Integer>();
t.put("A",new Integer(0));
t.put("AB",new Integer(1));
t.put("ABC",new Integer(2));
assertEquals( new Integer(0), t.get("A") );
assertEquals( new Integer(1), t.get("AB") );
assertEquals( new Integer(2), t.get("ABC") );
}
It its failing to get any items that I have put into the data structure.
My Hybrid TST PUT method:
public void put(String key, Object val) {
if (key == null) {
throw new InvalidKeyException();
}
for (int i = 0; i <1; i++) {
if (!Character.isLetter(key.charAt(i))) {
throw new InvalidKeyException();
}
}
int count = 0;
int position = 0;
position = 0;
for(char c: alphabet.toCharArray())
{
if(key.charAt(0)==c)
{
break;
}
position++;
}
size++;
myHybridTST[position].put(key, val);
}
In my TST class,
private static class Node {
private char c; // character
private Node left, mid, right; // left, middle, and right
// subtries
private Object val; // value associated with string
public Node[] next;
Node(char c) {
this.c = c;
}
}
public TST(char c) {
this.root = new Node(c);
}
I have no problem running your code, inserting and fetching values from the tree. However, it can be improved in some way:
Remove unused attributes
Use generics so you force the type of the elements you insert and fetch from the HybridTST and TST
Indentation is sometimes off
The code doesn't work as is (Node doesn't have method visit)
Instead of getting the position of the first letter on the alphabet, create a helper method for that.
Instead of calling new Integer(i), use Integer.valueOf(i)
From what I can see, your code contains the attribute of a 256-way trie plus the one for a ternary search tree, you should clean it
I'm working on converting a delimited file into an ordered tree structure. Below is a sample input...
1.2.3.4.5
1.3.2.4.5
1.2.4.5.6
I need to be able to convert this into an output like the following (in a searchable tree structure)...
1
-2
--3
---4
----5
--4
---5
----6
-3
--2
---4
----5
My thoughts on a solution to this was to...
Iterate the text file and create an arraylist that represents each row
Use Collections.sort() to make the arraylist sorted
Use a TreeMap to store the "base" record as a key (1 in this case) and an arrayList of strings to contain all the records
Iterate the TreeMap's keys and convert its arrayList to a LinkedHashSet that contains Nodes that represent each entry
Iterate the Tree's keys and print each node buy its index value
I thought everything was working well but when I started testing this approach, I found my output looks like below...
1
-2
--3
---4
----5
--4
---5
----6
-3
--2
As can be seen, the Nodes under 3/2/xx are not present, this is due to the logic I am using to build the LinkedHashSet for my Node values (Node(3, 4)) will simply be ignore because its a duplicate Node. I thought I was going in the right direction with this but now I can see my logic is clearly flawed. Does anyone have any suggestions for an approach for something like this? My current code is below...
TreeBuilder.java
public class TreeBuilder {
public static void main(String[] args) {
// Get a list of records
List<String> data = new ArrayList<String>();
data.add("1.2.3.4.5");
data.add("1.3.2.4.5");
data.add("1.2.4.5.6");
Collections.sort(data);
// Build the "Base" tree
TreeMap<String, List<String>> tree = buildBaseTree(data);
// Build the target tree structure
TreeMap<String, LinkedHashSet<Node>> finalTree = convertListToSet(tree);
printRecords(finalTree);
}
public static void printRecords(
TreeMap<String, LinkedHashSet<Node>> recordTree) {
System.out.println("---------Records---------");
for (Map.Entry<String, LinkedHashSet<Node>> entry : recordTree
.entrySet()) {
System.out.println(entry.getKey());
// Print out the structured data
StringBuilder stringBuilder = new StringBuilder();
Iterator<Node> iterator = entry.getValue().iterator();
while (iterator.hasNext()) {
Node node = iterator.next();
for (int i = 0; i < node.index; i++) {
stringBuilder.append("-");
}
System.out.println(stringBuilder.toString() + node.value);
// "reset" the builder
stringBuilder.setLength(0);
}
}
}
private static TreeMap<String, LinkedHashSet<Node>> convertListToSet(
TreeMap<String, List<String>> tree) {
TreeMap<String, LinkedHashSet<Node>> finalMap = new TreeMap<String, LinkedHashSet<Node>>();
LinkedHashSet<Node> linkedHashSet = new LinkedHashSet<Node>();
// Iterate the entry set
for (Map.Entry<String, List<String>> entry : tree.entrySet()) {
List<String> records = entry.getValue();
for (String record : records) {
String[] recordArray = record.split("\\.");
for (int i = 1; i < recordArray.length; i++) {
Node node = new Node(i, Integer.parseInt(recordArray[i]));
linkedHashSet.add(node);
}
}
finalMap.put(entry.getKey(), linkedHashSet);
// reset our linkedHashSet
linkedHashSet = new LinkedHashSet<Node>();
}
System.out.println("Final map " + finalMap);
return finalMap;
}
/**
* Builds a tree with base record keys and a list of records for each key.
*
* #param data
* #return
*/
private static TreeMap<String, List<String>> buildBaseTree(List<String> data) {
TreeMap<String, List<String>> tree = new TreeMap<String, List<String>>();
List<String> recordList = null;
// First find all base records
for (String record : data) {
String[] baseEntry = record.split("\\.");
if (!tree.containsKey(baseEntry[0])) {
recordList = new ArrayList<String>();
tree.put(baseEntry[0], recordList);
}
}
// Now place all sub-records in each base record
for (String record : data) {
String[] baseEntry = record.split("\\.");
tree.get(baseEntry[0]).add(record);
}
System.out.println("------------------Base Tree---------------");
System.out.println(tree);
System.out.println("------------------------------------------");
return tree;
}
private static List<String> readData(String file) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(new File(file)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
List<String> data = new ArrayList<String>();
// Get a list of all the records
String line = null;
try {
while ((line = bufferedReader.readLine()) != null) {
data.add(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// Sort the list so its ordered
System.out.println("-------------Sorted Data Set-----------");
Collections.sort(data);
for (String record : data) {
System.out.println(record);
}
System.out.println("---------------------------------------");
return data;
}
}
Node.java
public class Node implements Comparable<Node> {
int index;
int value;
public Node(int index, int value) {
this.index = index;
this.value = value;
}
public int getIndex() {
return index;
}
#Override
public String toString() {
return "Node [index=" + index + ", value=" + value + "]";
}
public void setIndex(int index) {
this.index = index;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
#Override
public int compareTo(Node o) {
Node otherNode = (Node) o;
if (this.index > otherNode.index)
return 1;
if (this.index < otherNode.index) {
return -1;
}
return 0;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + value;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (index != other.index)
return false;
if (value != other.value)
return false;
return true;
}
}
It doesn't have to be complicated. All you need is a SortedMap of SortedMap instances and there's only one trick to it: Parameterizing it recursively for type safety (if desired).
package com.acme;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
List<String> rows = new ArrayList<>();
rows.add("1.2.3.4.5");
rows.add("1.3.2.4.5");
rows.add("1.2.4.5.6");
MyTreeMap root = new MyTreeMap();
for (String row : rows) {
MyTreeMap n = root;
String[] cells = row.split("\\.");
for (String cell : cells) {
MyTreeMap child = n.get(cell);
if (child == null) {
n.put(cell, child = new MyTreeMap());
}
n = child;
}
}
print(root, "", "-");
}
static void print(MyTreeMap m, String indentationStr, String indentationStrAddition) {
for (Entry<String, MyTreeMap> o : m.entrySet()) {
System.out.println(indentationStr + o.getKey());
print(o.getValue(), indentationStr + indentationStrAddition, indentationStrAddition);
}
}
/**
* This is just a construct that helps us to parameterize recursively.
*/
static class MyTreeMap extends TreeMap<String, MyTreeMap> {private static final long serialVersionUID = 1L;}
}
If I understand your problem you want to create search trees from a list of integers that share common prefixes. If that's the case then I think you can achieve this with a lot less code:
private static class TreeNode {
private final Map<Integer, TreeNode> children = new HashMap<>();
public void insert(List<Integer> values) {
if (!values.isEmpty()) {
children.putIfAbsent(values.get(0), new TreeNode());
children.get(values.get(0)).insert(values.subList(1, values.size()));
}
}
public void print(int level) {
for (Map.Entry<Integer, TreeNode> entry : children.entrySet()) {
System.out.print(String.join("", Collections.nCopies(level, "-")));
System.out.println(entry.getKey());
entry.getValue().print(level + 1);
}
}
}
I'm not certain if you intend to sort the list of integers. If so you can add a Collections.sort at the appropriate place in the code.
I am designing a Hashtable with linear probing collision resolution. I have designed a capacity which defines the number of buckets, and a load factor. When the number of elements in the hashtable exceeds the product of the capacity and the load factor, the array should be rehashed. For some reason, the method is not even being called in my code. Here is my main method:
public class MyJHUHashMap<K extends Comparable<? super K>, V> implements JHUHashMap<K, V>{
private int cap;
private int numElements;
private double loadFactor;
private Node<K,V>[] hashtable;
public static void main(String[] args) {
MyJHUHashMap<Integer, Integer> m = new MyJHUHashMap<>();
m.put(1, 1);
m.put(2, 2);
m.put(3, 3);
m.put(4, 4);
m.put(5, 5);
m.put(6, 6);
m.put(7, 7);
System.out.println(m.cap);
System.out.println(m.size());
for(int i=0; i<m.hashtable.length; i++) {
if(m.hashtable[i] != null)
System.out.println(m.hashtable[i].key);
}
}
and here is my code:
private final class Node<K extends Comparable<? super K>, V> {
public K key;
public V val;
public Node() {
this.key = null;
this.val = null;
}
public Node(K theKey, V theValue) {
this.key = theKey;
this.val = theValue;
}
}
public MyJHUHashMap() {
this.cap = 11;
this.numElements = 0;
this.loadFactor = 0.5;
this.hashtable = new Node[cap];
}
public MyJHUHashMap(int pInitCap, double pLoadFactor) {
if(pInitCap > 0 && pLoadFactor > 0) {
this.cap = pInitCap;
this.loadFactor = pLoadFactor;
} else {
throw new IllegalArgumentException();
}
this.numElements = 0;
this.hashtable = new Node[cap];
}
#Override
public V put(K key, V value) {
if(containsKey(key)) {
int foundindex = find(key);
V prevObject = this.hashtable[foundindex].val;
//hashtable[foundindex] = new Node(key, value);
this.hashtable[foundindex].val = value;
return prevObject;
}
int index = key.hashCode() % cap;
if(this.hashtable[index] == null) {
this.hashtable[index] = new Node<K,V>(key, value);
this.numElements++;
return null;
}
boolean found = false;
//index += 1;
while(found) {
index += 1;
if(hashtable[index] == null) {
hashtable[index] = new Node<K,V>(key, value);
this.numElements++;
found = true;
//return null;
}
//index += 1;
}
if(this.numElements > this.cap * this.loadFactor) {
System.out.println("Rehashing...");
rehashAndResize();
}
return null;
}
public void rehashAndResize() {
//Node<K,V>[] temp = new Node[this.hashtable.length*2];
//Node<K,V>[] temp = new Node[this.hashtable.length*2];
System.out.println("Calling rehash method");
MyJHUHashMap<K,V> temp = new MyJHUHashMap<K, V>(this.hashtable.length * 2, this.loadFactor);
for(int i=0; i<this.hashtable.length; i++) {
temp.put(this.hashtable[i].key, this.hashtable[i].val);
}
this.hashtable = temp.hashtable;
}
"Rehashing" and "Calling rehash method" are not being printed, so the method is not being called, which I can't fathom why. I input 7 elements, and the hashtable prints out 7 correctly when I ask it the number of elements, so why isn't the condition being evaluated?
EDIT: Ok, after closer inspection I found that the rehash method was never being reached because the method was returning early. Thank you for your help!
I need to build a java service which extracts the value of a field at runtime. The path of the field in the canonical and the canonical document itself should be given as input.
Eg:
fromDoc consists of sub documents within it, in a hierarchy, ie.
fromDoc/Data/Parameters/outDate
•fromDoc
•Data
•Parameters
•outDate(string)
For inStringValues I give the input as 'fromDoc/Data/Parameters/outDate'
the output should return the value of the variable 'fromDoc/Data/Parameters/outDate' at run time.
I have a code which implements this with the key value pair logic.
IDataCursor pipelineCursor = pipeline.getCursor();
// fromDoc
IData fromDoc = IDataUtil.getIData( pipelineCursor, "fromDoc" );
String[] inStringValues = IDataUtil.getStringArray( pipelineCursor, "inStringValues" );
if ( fromDoc == null)
{
return;
}
pipelineCursor.destroy();
int len = inStringValues.length;
String[] outStrings = new String[len];
IDataCursor fromCursor = fromDoc.getCursor();
boolean hasData = false;
while( fromCursor.next() )
{
for(int i=0;i<len;i++)
{
String key = fromCursor.getKey();
String val = fromCursor.getValue().toString();
if(key.equals(inStringValues[i]))
{
outStrings[i]=key + "," + val;
}
}
}
fromCursor.destroy();
IDataCursor pipelineCursor_1 = pipeline.getCursor();
IDataUtil.put( pipelineCursor_1, "outStrings", outStrings );
pipelineCursor_1.destroy();
Please let me know how I can modify this code to implement the above mentioned logic?
Or let me know if anyone has such an existing service with you.
Tundra has a service that does exactly what you need: tundra.document:get($document, $key).
$document is the com.wm.data.IData document you want to extract the value from
$key is the name of the key you want to extract, and can be fully-qualified and include array indexing, for example "path/to/my[1]/key"
The relevant Java code is as follows:
public static final void get(IData pipeline) throws ServiceException {
IDataCursor cursor = pipeline.getCursor();
try {
IData document = IDataUtil.getIData(cursor, "$document");
String key = IDataUtil.getString(cursor, "$key");
IDataUtil.put(cursor, "$value", get(document, key));
} finally {
cursor.destroy();
}
}
// wrapper class for fully qualified IData keys
public static class Key {
public static final String SEPARATOR = "/";
public static final java.util.regex.Pattern INDEX_PATTERN = java.util.regex.Pattern.compile("\\[(-?\\d+?)\\]$");
protected boolean hasIndex = false;
protected int index = 0;
protected String key = null;
public Key(String key) {
java.util.regex.Matcher matcher = INDEX_PATTERN.matcher(key);
StringBuffer buffer = new StringBuffer();
while(matcher.find()) {
hasIndex = true;
index = Integer.parseInt(matcher.group(1));
matcher.appendReplacement(buffer, "");
}
matcher.appendTail(buffer);
this.key = buffer.toString();
}
public boolean hasIndex() {
return hasIndex;
}
public int getIndex() {
return index;
}
public String toString() {
return key;
}
public static java.util.Queue<Key> parse(String key) {
String[] parts = key.split(SEPARATOR);
java.util.Queue<Key> queue = new java.util.ArrayDeque<Key>(parts.length);
for (int i = 0; i < parts.length; i++) {
queue.add(new Key(parts[i]));
}
return queue;
}
public static boolean isFullyQualified(String key) {
return key != null && (key.contains(SEPARATOR) || INDEX_PATTERN.matcher(key).find());
}
}
// returns the value associated with the given key from the given IData document
public static Object get(IData input, String key) {
Object value = null;
if (input != null && key != null) {
// try finding a value that matches the literal key
IDataCursor cursor = input.getCursor();
try {
value = IDataUtil.get(cursor, key);
} finally {
cursor.destroy();
}
// if value wasn't found using the literal key, the key could be fully qualified
if (value == null && Key.isFullyQualified(key)) value = get(input, Key.parse(key));
}
return value;
}
// gets a value from an IData document with a fully qualified key
protected static Object get(IData input, java.util.Queue<Key> keys) {
Object value = null;
if (input != null && keys != null && keys.size() > 0) {
IDataCursor cursor = input.getCursor();
Key key = keys.remove();
if (keys.size() > 0) {
if (key.hasIndex()) {
IData[] array = IDataUtil.getIDataArray(cursor, key.toString());
value = get(get(array, key.getIndex()), keys);
} else {
value = get(IDataUtil.getIData(cursor, key.toString()), keys);
}
} else {
if (key.hasIndex()) {
Object[] array = IDataUtil.getObjectArray(cursor, key.toString());
value = get(array, key.getIndex());
} else {
value = IDataUtil.get(cursor, key.toString());
}
}
cursor.destroy();
}
return value;
}
public static <T> T get(T[] array, int index) {
T item = null;
if (array != null) {
// support reverse/tail indexing
if (index < 0) index += array.length;
item = array[index];
}
return item;
}
Note: Tundra has a complementary service for setting a value in a com.wm.data.IData document too: tundra.document.put($document, $key, $value).
What about this ?
// fromDoc
IDataCursor cursor = pipeline.getCursor();
IData fromDoc = IDataUtil.getIData(cursor, "fromDoc");
if (fromDoc == null) {
return;
}
// Data
cursor = fromDoc.getCursor();
IData Data = IDataUtil.getIData(cursor, "Data");
if (Data == null) {
return;
}
// Parameters
cursor = Data.getCursor();
IData Parameters = IDataUtil.getIData(cursor, "Parameters");
if (Parameters == null) {
return;
}
// outDate
cursor = Parameters.getCursor();
String outDate = IDataUtil.getString(cursor, "outDate");
// Here I have the outDate value
Anyone knows a good Java library I can use to parse a Newick file easily? Or if you have some tested source code I could use?
I want to read the newick file: http://en.wikipedia.org/wiki/Newick_format in java and generate a visual representation of the same. I have seen some java programs that do that but not easy to find how the parsing works in code.
Check out jebl (Java Evolutionary Biology Library) of FigTree and BEAST fame. Probably a lot more tree functionality than you might need, but it's a solid library.
Stumbled on this question while looking for a Java Newick parser.
I've also come across libnewicktree, which appears to be an updated version of the Newick parser from Juxtaposer.
I like to use the Archaeopteryx library based on the forester libraries. It can do a lot more than parsing and visualizing trees but its usage remains very simple even for basic tasks:
import java.io.IOException;
import org.forester.archaeopteryx.Archaeopteryx;
import org.forester.phylogeny.Phylogeny;
public class PhylogenyTree {
public static void main(String[] args) throws IOException{
String nhx = "(mammal,(turtle,rayfinfish,(frog,salamander)))";
Phylogeny ph = Phylogeny.createInstanceFromNhxString(nhx);
Archaeopteryx.createApplication(ph);
}
}
Here is a Newick parser I wrote for personal use. Use it in good health; there is no visualization included.
import java.util.ArrayList;
/**
* Created on 12/18/16
*
* #author #author Adam Knapp
* #version 0.1
*/
public class NewickTree {
private static int node_uuid = 0;
ArrayList<Node> nodeList = new ArrayList<>();
private Node root;
static NewickTree readNewickFormat(String newick) {
return new NewickTree().innerReadNewickFormat(newick);
}
private static String[] split(String s) {
ArrayList<Integer> splitIndices = new ArrayList<>();
int rightParenCount = 0;
int leftParenCount = 0;
for (int i = 0; i < s.length(); i++) {
switch (s.charAt(i)) {
case '(':
leftParenCount++;
break;
case ')':
rightParenCount++;
break;
case ',':
if (leftParenCount == rightParenCount) splitIndices.add(i);
break;
}
}
int numSplits = splitIndices.size() + 1;
String[] splits = new String[numSplits];
if (numSplits == 1) {
splits[0] = s;
} else {
splits[0] = s.substring(0, splitIndices.get(0));
for (int i = 1; i < splitIndices.size(); i++) {
splits[i] = s.substring(splitIndices.get(i - 1) + 1, splitIndices.get(i));
}
splits[numSplits - 1] = s.substring(splitIndices.get(splitIndices.size() - 1) + 1);
}
return splits;
}
private NewickTree innerReadNewickFormat(String newick) {
// single branch = subtree (?)
this.root = readSubtree(newick.substring(0, newick.length() - 1));
return this;
}
private Node readSubtree(String s) {
int leftParen = s.indexOf('(');
int rightParen = s.lastIndexOf(')');
if (leftParen != -1 && rightParen != -1) {
String name = s.substring(rightParen + 1);
String[] childrenString = split(s.substring(leftParen + 1, rightParen));
Node node = new Node(name);
node.children = new ArrayList<>();
for (String sub : childrenString) {
Node child = readSubtree(sub);
node.children.add(child);
child.parent = node;
}
nodeList.add(node);
return node;
} else if (leftParen == rightParen) {
Node node = new Node(s);
nodeList.add(node);
return node;
} else throw new RuntimeException("unbalanced ()'s");
}
static class Node {
final String name;
final int weight;
boolean realName = false;
ArrayList<Node> children;
Node parent;
/**
* #param name name in "actualName:weight" format, weight defaults to zero if colon absent
*/
Node(String name) {
int colonIndex = name.indexOf(':');
String actualNameText;
if (colonIndex == -1) {
actualNameText = name;
weight = 0;
} else {
actualNameText = name.substring(0, colonIndex);
weight = Integer.parseInt(name.substring(colonIndex + 1, name.length()));
}
if (actualNameText.equals("")) {
this.realName = false;
this.name = Integer.toString(node_uuid);
node_uuid++;
} else {
this.realName = true;
this.name = actualNameText;
}
}
#Override
public int hashCode() {
return name.hashCode();
}
#Override
public boolean equals(Object o) {
if (!(o instanceof Node)) return false;
Node other = (Node) o;
return this.name.equals(other.name);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (children != null && children.size() > 0) {
sb.append("(");
for (int i = 0; i < children.size() - 1; i++) {
sb.append(children.get(i).toString());
sb.append(",");
}
sb.append(children.get(children.size() - 1).toString());
sb.append(")");
}
if (name != null) sb.append(this.getName());
return sb.toString();
}
String getName() {
if (realName)
return name;
else
return "";
}
}
#Override
public String toString() {
return root.toString() + ";";
}
}
Seems like Tree Juxtaposer includes a newick tree parser (however limited to only one tree per file).