Remove item of record without knowing all item - elm

I have this simulation:
init : (Model, Cmd Msg)
init = ({ dog = List Dog }, Cmd.none)
type alias Dog =
{ name : String
, age : Int
, price : Float
, extra = List Extra
}
type alias Extra =
{ allergies : List String
, wishes : List String
}
[{ name = "Hot"
, age = 1
, price = 300.5
, extra = [{...}]
},
{ name = "Dog"
, age = 3
, price = 150.0
, extra = [{...}]
}]
And I want to remove only 'extras' of Dog, in determined part of the code:
[{ name = "Hot"
, age = 1
, price = 300.5
},
{ name = "Dog"
, age = 3
, price = 150.0
}]
I can do this by mapping the entire list and generating a new one by removing 'extra' occurrence:
removeExtraOfDogs dogList =
(dogList |> List.map (\dog ->
{ name = dog.name
, age = dog.age
, price = dog.price
}
))
but I want to make it dynamic to just pass the extra to remove, without having to know what variables there are in the type and recreate it

Elm used to have this feature but it was removed a while ago. But, based on your use case described in a comment, I don't think you need this feature. You can instead use extensible record feature of Elm to allow passing different records into a function as long as they contain a fixed set of fields.
For example, let's say you have two types with name and age fields and having an extra incompatible field:
type alias Foo = { name : String, age : Int, extra : List String }
type alias Bar = { name : String, age : Int, extra : Int }
You can define a function that takes a record with a name field of type String and age of type Int and any extra fields:
encode : { r | name : String, age : Int } -> String
encode record = record.name ++ "," ++ toString record.age
You'll can now pass both Foo and Bar to this function because they both satisfy the requirements of the type signature.

Related

using exposed and I want to use subquery by condition using caseWhenElse inside slice [kotlin, exposed]

val cor = TCorridor.slice(corridorNm).select{
TCorridor.corridorId eq TFlightPathSegment.corridorId
}
val corPo = TCorridorPoint.slice(pointNm).select{
TCorridorPoint.pointId eq TFlightPathSegment.pointId
}
val pNm = SubQueryExpression<String>(corPo.alias(""))
val cNm = SubQueryExpression<String>(cor.alias(""))
The reason why the alias is blank is that the alias is attached after the subquery in the case statement, causing an error.
val typeNm =
Expression.build {
case()
.When((TFlightPathSegment.fltPathType eq "POINT"), pNm)
.Else(cNm)
}
val query = TFlightPathSegment
.slice(TFlightPathSegment.fltPathId, TFlightPathSegment.sortOrd, TFlightPathSegment.fltPathType, TFlightPathSegment.pointId, TFlightPathSegment.corridorId
, typeNm
).select { TFlightPathSegment.fltPathId eq fltPathId1 }
.groupBy(TFlightPathSegment.fltPathId, TFlightPathSegment.sortOrd)
.orderBy(TFlightPathSegment.sortOrd)
The sql of the variable name query is output normally.
Get the value of each field using query.map{}
query.map {
println("case1 ---------- ")
println(it) // if print it ↓
it = TFlightPathSegment.fliPathId = "", TFlightPathSegment.sortOrd = "", CASE WHEN TFlightPathSegment.fltPathType = "POINT" THEN (SELECT POINT_NM FROM TCorridorPoint where point_id = TFlightPathSegment.flt) = "POINT_NM"
}
I want to get the value returned from the case statement
if print it[typeNm] returned boolean Type
but i want return value of subquery by condition
What am I missing?

how to link variables so when i modify one of them both are modified? or just the top level one

I have 3 variables A,b and c in a class called ONE
var a = 0
var b = 0
var c = 0
that class(class ONE) is abstract and is used by 3 classes(TWO, THREE, FOUR). the variable selected changes by using a when statement.
var chosenVariable:Long
chosenVariable= when (sign){
1-> a
2-> b
3-> c
else -> a
}
note that sign is what the user inputs to decide which variable is chosen.
my question is. when i modify chosenVariable I want it to change whatever variable it was set a, b or c.
is this possible? I thought it might be called instancing, but I can't seem to come up with anything searching that way. I think i need to do it somehow with a setter and getter?
You can use KMutableProperty0<> class to hold reference to primitive variables:
var chosenVariable: KMutableProperty0<Long> = when (sign) {
1-> ::a
2-> ::b
3-> ::c
else -> ::a
}
// set value
chosenVariable.set(7)
It is currently available only for global variables. Here is some useful info.
If you mean chosenVariable is the sign, either:
there can be another function to set/get chosen variables (a, b, c), such as:
var chosenVariable : Long = 0 // init value
fun set ( value : Int ) {
when ( chosenVariable ) {
// 1 -> a = value
2 -> b = value
3 -> c = value
else -> a = value
}
}
fun get ( ) {
return when ( chosenVariable ) {
// 1 -> a
2 -> b
3 -> c
else -> a
}
}
or maybe use MutableMap instead:
val variables = mutableMapOf <Long /* sign */, Int /* value */> (
1 to 0, // a
2 to 0, // b
3 to 0, // c
)
// still with getter/setter like before, but with map
fun get ( ) = variables [ chosenVariable ]
fun set ( value : Int ) {
variables [ chosenVariable ] = value
}

How to merge two different classes data into one in Kotlin

I have use two different classes:
ListTitle.kt
class ListTitle {
var id: Int? = null
var title: String? = null
constructor(id:Int, title: String) {
this.id = id
this.title = title
}
}
ListDes.kt
class ListDes {
var address: Int? = null
var des: String? = null
constructor(address: Int, des: String) {
this.address = address
this.des = des
}
}
listOfTitle and listDes are ArrayLists:
listOfTitle.add(ListTitle(1, "Hello"))
listOfTitle.add(ListTitle(2, "World"))
listDes.add(ListDes(1, "World Des"))
listDes.add(ListDes(2, "Hello Des"))
I want to assign title of ListTitle to des of ListDes by matching them by id/address for each element of the two lists.
How can I approach this?
You can use zip to merge two lists into one which has Pairs as elements.
val listOfTitle = listOf(ListTitle(1, "Hello"), ListTitle(2, "World"))
val listDes = listOf(ListDes(1, "World Des"), ListDes(2, "Hello Des"))
val pairList = listOfTitle.zip(listDes)
// since an element in the new list is a pair, we can use destructuring declaration
pairList.forEach { (title, des) ->
println("${title.title} ${des.des}")
}
Output:
Hello World Des
World Hello Des
A few notes:
You can write your classes in a shorter form in Kotlin. Just put the properties directly in the argument list of the primary constructor like shown below.
class ListTitle(
var id: Int? = null,
var title: String? = null
)
class ListDes(
var address: Int? = null,
var des: String? = null
)
Don't overuse nullability (using Int? instead of Int for instance). Make properties only nullable if necessary. If you always pass in arguments for the specified properties there is not need for them to be nullable.
Maybe you should choose other names for the classes (without "List" in it) since they are actually elements of a List in your example and not lists themselves.
If you just want to print the values you could do this:
listOfTitle.forEach {
val id = it.id
println(it.title + " " + listDes.filter { it.address == id }[0].des)
}
will print the matching des for each id:
Hello World Des
World Hello Des
The above code is supposed to work when both lists have the same length and there is always a matching des for each id
if you want to create a new list with the matching pairs:
val newList = listOfTitle.map { it ->
val id = it.id
Pair(it.title, listDes.filter { it.address == id }[0].des)
}
newList.forEach { println(it.first + " " + it.second) }

Transform string in key variable name

There is the possibility of converting a string to a key, eg:
type alias Model =
{ sun : Int -- Init with 0
, moon : Int -- Init with 0
}
What I want to achieve:
let
userSelect = "sun";
in
({ model | userSelect = 1 }, Cmd.none) -- ugly to be easy to understand
After model.sun should 1
You won't be able to do exactly what you want as access to records does not work that way. In your case i would recommend a Dictionary
type alias Model =
{ planets : Dict String Int
}
planets =
Dict.fromList
[ ("sun", 0)
, ("moon": 0)
]
model = { planets = planets }
and then
let
userSelect = "sun";
in
({ model | planets = Dict.insert userSelect 1 model.planets }, Cmd.none)

Setting values in aliased records

I'm just starting out with Elm, so be nice:)
In the "Random" example of the official Elm Guide the model seems to be initialized with the value 1 like this:
type alias Model =
{ dieFace : Int
}
init : (Model, Cmd Msg)
init =
(Model 1, Cmd.none)
My understanding of this is that the code
Model 1
sets the value of the dieFace attribute in the record. Is this correct and if so: what is this strange syntax for setting the attribute of a record? I would have expected something along the lines of
{ model | dieFace = 1 }
Model is a type alias for a record which has a single int value called dieFace.
There are a few ways to create a value of that type:
Model 1 -- treats Model as a function with a single parameter
{ dieFace = 1 } -- creates a record that happens to coincide with the Model alias
The strange syntax you see in { model | dieFace = 1 } is short-hand for creating a new value based off an existing record value but changing one or more fields. It perhaps doesn't make much sense when your record type has a single field so let's create an arbitrary example:
type alias ColoredDie = { dieFace: Int, color: String }
You can play around in the Elm REPL and perhaps this will help it make sense:
> blue3 = ColoredDie 3 "blue"
{ dieFace = 3, color = "blue" } : Repl.ColoredDie
> red3 = { blue3 | color = "red" }
{ dieFace = 3, color = "red" } : { dieFace : Int, color : String }
> red4 = { red3 | dieFace = 4 }
{ dieFace = 4, color = "red" } : { color : String, dieFace : number }
> green6 = { red4 | color = "green", dieFace = 6 }
{ dieFace = 6, color = "green" } : { color : String, dieFace : number }
You can read up on Elm's record syntax here.