I want to decode a JSON array of payload objects into List Payload where each Payload is a custom type:
type Payload
= PayloadP1 P1
| PayloadP2 P2
After decoding PayloadP1 and PayloadP2 using decoders below how do I decode Payload?
type alias P1 =
{ id : Int
, st : String
}
type alias P2 =
{ id : Int
, s1 : String
, s2 : String
}
type Payload
= PayloadP1 P1
| PayloadP2 P2
type alias PayloadQueue = List Payload
decodeP1 : Jd.Decoder P1
decodeP1 =
Jd.map2 P1
(Jd.field "id" Jd.int)
(Jd.field "st" Jd.string)
decodeP2 : Jd.Decoder P2
decodeP2 =
Jd.map3 P2
(Jd.field "id" Jd.int)
(Jd.field "p1" Jd.string)
(Jd.field "p2" Jd.string)
decodePayload =
Jd.field ".type" Jd.string
|> Jd.andThen decodePayload_
{-
decodePayload_ : String -> Jd.Decoder Payload
decodePayload_ ptype =
case ptype of
"P1" -> decodeP1
"P2" -> decodeP2
-}
json_str = """[
{".type" : "P1", "id" : 1, "st" : "st"},
{".type" : "P2", "id" : 2, "p1" : "p1", "p2" : "p2"},
]"""
You need to wrap P1 and P2 in PayloadP1 and PayloadP2 respectively in order to return a common type from each branch, which you can do using map. Then you also need to account for the possibility that the type field is neither P1 or P2. In that case you can either provide a default or return an error using fail. I've done the latter below.
decodePayload_ : String -> Jd.Decoder Payload
decodePayload_ ptype =
case ptype of
"P1" -> decodeP1 |> Jd.map PayloadP1
"P2" -> decodeP2 |> Jd.map PayloadP2
_ -> Jd.fail "invalid type"
I have two data types and a transformation function to convert from one to another
data TTerm : Set where
TVar : Nat -> TTerm
TPrim : TPrim' -> TTerm
TDef : QName -> TTerm
TCon : QName -> TTerm
TLam : TTerm -> TTerm
TApp : TTerm -> List TTerm -> TTerm
TLet : TTerm -> TTerm -> TTerm
TLit : Literal -> TTerm
TErased : TTerm
TError : TError' -> TTerm
data GoTerm : Set where
Self : GoTerm
Local : LocalId -> GoTerm
Global : GlobalId -> GoTerm
GoVar : Nat -> GoTerm
GoSwitch : GoTerm -> List GoTerm -> GoTerm
GoCase : MemberId -> Nat -> Nat -> Nat -> List GoTerm -> GoTerm
GoMethodCall : MemberId -> List GoTerm -> GoTerm
GoMethodCallParam : GoTerm -> TypeId -> GoTerm
GoCreateStruct : MemberId -> List GoTerm -> GoTerm
GoIf : GoTerm -> GoTerm -> GoTerm -> GoTerm
GoLet : String -> GoTerm -> GoTerm -> GoTerm
PrimOp : GoTerm -> GoTerm -> GoTerm -> GoTerm
ReturnExpression : GoTerm -> TypeId -> GoTerm
GoInt : Nat -> GoTerm
Const : String -> GoTerm
UndefinedTerm : GoTerm
GoErased : GoTerm
Null : GoTerm
I have also created additional function that maps back from GoTerm to TTerm, so now I have two functions that do opposite things and would like to prove that a ≡ (decompileTerm (compileTerm a)). But so far have not found a way to do that, maybe someone could put me on the right tracks here?
I have a collection structure as shown below. I need to build the statement based on k,v pairs in the map. The level of nesting is not known prior and code needs to parse it dynamically.
Structure:
case class Step(id: Option[String], stepId: Option[String], parameters: Option[Map[String, Any]])
val sample = Step(id = Some("a1"), Some("case"), Some(
Map(
"CONDITIONAL" -> List(
Map("comparison" -> List(
Map("comparision" -> List(
Map("comparision" -> List(
Map("comparator" -> List(
Map(
"EVAL" -> "c11",
"OPERATION" -> "equals to",
"WHEN" -> List("A")),
Map(
"eval" -> "c12",
"operation" -> "in",
"when" -> List("B")),
Map(
"eval" -> "c13",
"operation" -> "starts with",
"when" -> List("C")
)),
"operator" -> "OR"
),
Map("comparator" -> List(
Map(
"EVAL" -> "c21",
"OPERATION" -> "equals to",
"WHEN" -> List("A")),
Map(
"eval" -> "c22",
"operation" -> "in",
"when" -> List("B")
)),
"operator" -> "OR"
)),
"operator" -> "AND"
),
Map("comparator" -> List(
Map(
"EVAL" -> "c31",
"OPERATION" -> "equals to",
"WHEN" -> List("A")),
Map(
"EVAL" -> "c32",
"OPERATION" -> "in",
"WHEN" -> List("B")),
Map(
"EVAL" -> "c33",
"OPERATION" -> "starts with",
"WHEN" -> List("C")
)),
"operator" -> "OR"
)),
"operator" -> "OR"
)),
"THEN" -> "result"
)),
"ELSE" -> "default"
))
)
val stepsLower = sample.parameters.get.map(p => p._1.toLowerCase -> p._2)
val comparisons = stepsLower("conditional").asInstanceOf[List[Map[String, Any]]]
Now I need to parse data under the conditional (in comparisons) by evaluating the structure.
The result should be ((c11 OR c12 OR c13 ) AND (c21 OR c22)) OR (c31 OR c32 OR c33 OR c34)
Here is the code snippet that should work for all your use cases.
case class Step(id: Option[String], stepId: Option[String], parameters: Option[Map[String, Any]])
val sample1 = Step(id = Some("a1"), Some("case"), Some(Map(
"CONDITIONAL" -> List(
Map("comparison" -> List(
Map("comparison" -> List(
Map("comparison" -> List(
Map("comparator" -> List(
Map(
"eval" -> "c11",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c12",
"operation" -> "in",
"when" -> List("B")),
Map(
"eval" -> "c13",
"operation" -> "starts with",
"when" -> List("C")
)),
"operator" -> "OR"
),
Map("comparator" -> List(
Map(
"eval" -> "c21",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c22",
"operation" -> "in",
"when" -> List("B")
)),
"operator" -> "OR"
)),
"operator" -> "AND"
),
Map("comparator" -> List(
Map(
"eval" -> "c31",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c32",
"operation" -> "in",
"when" -> List("B")),
Map(
"eval" -> "c33",
"operation" -> "starts with",
"when" -> List("C")
)),
"operator" -> "OR"
)),
"operator" -> "OR"
)),
"then" -> "result"
)),
"else" -> "default"
))
)
val sample2 = Step(id = Some("a1"), Some("case"), Some(
Map(
"conditional" -> List(
Map("comparison" -> List(
Map("comparison" -> List(
Map("comparator" -> List(
Map(
"eval" -> "c11",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c12",
"operation" -> "in",
"when" -> List("B", "b"))),
"operator" -> "AND"),
Map("comparator" -> List(
Map("eval" -> "c21",
"operation" -> "equals to",
"when" -> List("A")),
Map("eval" -> "c31",
"operation" -> "equals to",
"when" -> List("A"))),
"operator" -> "OR")),
"operator" -> "OR")),
"then" -> "something"
),
Map("comparison" -> List(
Map("comparison" -> List(
Map("comparator" -> List(
Map(
"eval" -> "c111",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c121",
"operation" -> "in",
"when" -> List("B", "b"))
),
"operator" -> "AND"),
Map("comparator" -> List(
Map(
"eval" -> "c212",
"operation" -> "equals to",
"when" -> List("A")),
Map(
"eval" -> "c313",
"operation" -> "equals to",
"when" -> List("A"))
),
"operator" -> "OR")),
"operator" -> "AND")),
"then" -> "somethingelse")
),
"else" -> "default"
)
))
def constructCase(c: List[Map[String, Any]], parentOp: Option[String] = None, parentThen: Option[String] = None): String = {
val result = c.map { x =>
val currentOp: Option[String] = x.get("operator").asInstanceOf[Option[String]]
val currentThen: Option[String] = x.get("then").asInstanceOf[Option[String]]
if (x contains "comparator") {
"(" + x("comparator").asInstanceOf[List[Map[String, Any]]].map(x => s"${x("eval")} ${x("operation")} ${x("when").asInstanceOf[List[String]].mkString(",")}").mkString(" " + currentOp.getOrElse("") + " ") + ")"
} else {
val tmp = constructCase(x("comparison").asInstanceOf[List[Map[String, Any]]], currentOp, currentThen)
if (tmp contains "WHEN") tmp else "(" + tmp + ")"
}
}.mkString(if (parentOp.isDefined) s" ${parentOp.get} " else "")
if (parentThen.isDefined) s"WHEN $result THEN ${parentThen.get}\n" else result.trim
}
val samples = Set(sample1, sample2)
samples.foreach { sample =>
val stepsLower = sample.parameters.get.map(p => p._1.toLowerCase -> p._2)
val comparisons = stepsLower("conditional").asInstanceOf[List[Map[String, Any]]]
println("CASE \n" + constructCase(comparisons) + s"\nELSE ${stepsLower("else")}")
println("")
}
Here is the result
CASE
WHEN (((c11 equals to A OR c12 in B OR c13 starts with C) AND (c21 equals to A OR c22 in B)) OR (c31 equals to A OR c32 in B OR c33 starts with C)) THEN result
ELSE default
CASE
WHEN ((c11 equals to A AND c12 in B,b) OR (c21 equals to A OR c31 equals to A)) THEN something
WHEN ((c111 equals to A AND c121 in B,b) AND (c212 equals to A OR c313 equals to A)) THEN somethingelse
ELSE default
Let me know if it doesn't work for any of your use case.
How can I convert the following Map structure which is a Map[String,Any] to a Json in scala? I am using Play.
val result = s
.groupBy(_.dashboardId)
.map(
each => Map(
"dashboardId" -> each._1,
"cubeId" -> each._2.head.cubeid,
"dashboardName" -> each._2.head.dashboardName,
"reports" -> each._2.groupBy(_.reportId).map(
reportEach => Map(
"reportId" -> reportEach._1,
"reportName" -> reportEach._2.head.reportName,
"selectedColumns" -> reportEach._2.groupBy(_.selectedColumnid).map(
selectedColumnsEach => Map(
"selectedColumnId" -> selectedColumnsEach._1,
"columnName" ->
selectedColumnsEach._2.head.selectColumnName.orNull,
"seq" ->selectedColumnsEach._2.head.selectedColumnSeq,
"formatting" -> selectedColumnsEach._2
)
)
)
)
)
)
You cannot convert a Map[String, Any] to Json but you can convert a Map[String, String] or Map[String, JsValue].
In your case, you can do by converting each map value to a JsValue before hand with:
Map(
"dashboardId" -> Json.toJson(each._1),
"cubeId" -> Json.toJson(each._2.head.cubeid),
"dashboardName" -> Json.toJson(each._2.head.dashboardName),
"reports" -> Json.toJson(each._2.groupBy(_.reportId).map(
reportEach => Map(
"reportId" -> Json.toJson(reportEach._1),
"reportName" -> (reportEach._2.find(_.reportName != null) match {
case Some(reportNameData) => Json.toJson(reportNameData.reportName)
case None => JsNull
})),
...
)
I read the results into a Seq[Map[String,Any]] by using .toSeq and then used toJson to convert it into a Json this worked.
val s = new SaveTemplate getReportsWithDashboardId(dashboardId)
val result : Seq[Map[String,Any]] = s.groupBy(_.dashboardId)
.map(
each => Map(
"dashboardId" -> each._1,
"cubeId" -> each._2.head.cubeid,
"dashboardName" -> each._2.head.dashboardName,
"reports" -> each._2.groupBy(_.reportId).map(
reportEach => Map(
"reportId" -> reportEach._1,
"reportName" -> (reportEach._2.find(_.reportName != null) match {
case Some(reportNameData) => reportNameData.reportName
case None => null
}),
"selectedColumns" -> reportEach._2.groupBy(_.selectedColumnid).map(
selectedColumnsEach => Map(
"selectedColumnId" -> selectedColumnsEach._1,
"columnName" -> selectedColumnsEach._2.head.selectColumnName.orNull,
"seq" ->selectedColumnsEach._2.head.selectedColumnSeq,
"formatting" -> Map(
"formatId" -> (selectedColumnsEach._2.find(_.formatId != null) match {
case Some(reportNameData) => reportNameData.formatId
case None => null
}),
"formattingId" -> (selectedColumnsEach._2.find(_.formattingid != null)
match {
case Some(reportNameData) => reportNameData.formattingid
case None => null
}),
"type" -> (selectedColumnsEach._2.find(_.formattingType != null) match
{
case Some(reportNameData) => reportNameData.formattingType
case None => null
})
)
)
)
)
)
)
).toSeq
val k = toJson(result)
Ok(k)
I want to reduce list of tuples that have a common field such as x by summing y fields.
Input:
List(("x" -> "foo", "y" -> 1000),
("x" -> "foo", "y" -> 1),
("x" -> "bar", "y" -> 101))
Output:
List(("x" -> "foo", "y" -> 1001),
("x" -> "bar", "y" -> 101))
What is the good approach for that? foldLeft or reduce?
Your item should be tuple:
List(("x" -> "foo", "y" -> 1000),("x" -> "foo", "y" -> 1), ("x" -> "bar", "y" -> 101))
use groupBy to group your key, and mapValues to generate the target:
List(("x" -> "foo", "y" -> 1000),("x" -> "foo", "y" -> 1), ("x" -> "bar", "y" -> 101))
.groupBy(x => x._1)
.mapValues(t => t.head._2._1 -> t.foldLeft(0.0)(_ + _._2._2))
The Output:
scala.collection.immutable.Map[(String, String),(String, Double)] =
Map((x,foo) -> (y,1001.0), (x,bar) -> (y,101.0))