Skip to content

Instantly share code, notes, and snippets.

@sshark
Last active June 30, 2022 15:47
Show Gist options
  • Save sshark/620c58e978abfc6461b537c8e0442f6b to your computer and use it in GitHub Desktop.
Save sshark/620c58e978abfc6461b537c8e0442f6b to your computer and use it in GitHub Desktop.
package org.teckhooi.bar;
import java.util.Map;
import java.util.Objects;
public class Leaf implements Tree {
private String value;
public Leaf(String value) {
this.value = value;
}
@Override
public Map<String, Tree> getAttributes() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
@Override
public String getValue() {
return value;
}
}
package org.teckhooi.compositekey
import io.circe.*
import io.circe.generic.semiauto.*
import io.circe.syntax.*
import scala.collection.immutable.ListMap
sealed trait Tree
case class Node(attributes: Map[String, Tree]) extends Tree
case class Leaf(value: String) extends Tree
object MapOfTreeApp extends App {
val source = ListMap(
"grp1" -> "abc",
"grp1.grp4.attr2-2" -> "profile-9-value2",
"grp1.attr2-1" -> "profile-9-value1",
"grp3.attr2-1" -> "profile-9-value1"
// "grp1" -> "def"
)
def extractKeys(
arr: List[String],
value: String,
ys: List[String] = Nil
): Map[String, Tree] = arr match {
case Nil => Map.empty[String, Tree]
case x :: Nil =>
val last: Map[String, Tree] = Map(x -> Leaf(value))
ys.foldLeft(last)((m, k) => Map(k -> Node(m)))
case x :: xs => extractKeys(xs, value, x :: ys)
}
def merge(first: Map[String, Tree], second: Map[String, Tree]): Map[String, Tree] =
(first.keySet ++ second.keySet)
.map(key => key -> mergeValues(first.get(key), second.get(key)))
.toMap
def mergeValues(first: Option[Tree], second: Option[Tree]): Tree = (first, second) match {
case (_, Some(Leaf(v))) => Leaf(v)
case (Some(Leaf(v)), Some(Node(m))) => Node(m)
case (Some(Node(m)), Some(Node(n))) => Node(merge(m, n))
case _ => first.orElse(second).get
}
val target: Map[String, Tree] = source.foldLeft(Map.empty[String, Tree]) { case (m, (k, v)) =>
merge(m, extractKeys(k.split("\\.").toList, v))
}
println(s"Raw => $target\n")
implicit val treeDecoder: Decoder[Tree] = deriveDecoder
implicit val treeEncoder: Encoder[Tree] =
case Node(attrs) => attrs.asJson
case Leaf(value) => Json.fromString(value)
println(s"JSON => ${target.asJson}")
}
package org.teckhooi.bar;
import java.util.Map;
import java.util.Objects;
public class Node implements Tree {
private Map<String, Tree> attributes;
public Node(Map<String, Tree> attributes) {
this.attributes = attributes;
}
@Override
public Map<String, Tree> getAttributes() {
return attributes;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public String getValue() {
return null;
}
}
package org.teckhooi.bar;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import jdk.jshell.spi.ExecutionControl;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
public class RunMe {
public static void main(String[] args) {
Map<String, String> source = new LinkedHashMap<>();
// source.put("root.org1.employee1", "alice");
// source.put("root.org2", "bob");
source.put("grp1", "abc");
source.put("grp1.grp2.attr2-2", "profile-9-value2");
source.put("grp1.attr2-1", "profile-9-value1");
// source.put("grp1", "def");
Map<String, Tree> root = new HashMap<>();
for (Map.Entry<String, String> entry : source.entrySet()) {
String[] split = entry.getKey().split("\\.");
String topName = split[0];
Tree next = root.get(topName);
if (Objects.isNull(next)) {
next = split.length > 1 ? new Node() : new Leaf(entry.getValue());
root.put(topName, next);
} else {
if (next.isLeaf()) {
next = new Node();
root.put(topName, next);
}
}
if (split.length == 1) {
root.put(topName, new Leaf(entry.getValue()));
continue;
}
for (int i = 1; i < split.length - 1; i++) {
String attrName = split[i];
Map<String, Tree> children = next.getAttributes();
Tree next2 = children.get(attrName);
if (Objects.isNull(next2)) {
if (i == split.length - 1) {
children.put(attrName, new Leaf(entry.getValue()));
continue;
} else {
next2 = new Node();
children.put(attrName, next2);
}
}
next = next2;
}
next.getAttributes().put(split[split.length - 1], new Leaf(entry.getValue()));
}
TypeAdapter<Leaf> leafTypeAdapter = new TypeAdapter<Leaf>() {
@Override
public void write(JsonWriter out, Leaf value) throws IOException {
out.jsonValue(String.format("\"%s\"", value.getValue()));
}
@Override
public Leaf read(JsonReader in) throws IOException {
throw new RuntimeException("not implemented");
}
};
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(Leaf.class, leafTypeAdapter).create();
System.out.println(gson.toJson(root));
}
}
package org.teckhooi.bar;
import java.util.Map;
public interface Tree {
Map<String, Tree> getAttributes();
boolean isLeaf();
String getValue();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment