initialization of fsharp class field - xaml

I have a class bound to a XAML file.
Upon the first call to it, the field selectedudl is = null.
Do you know why it is the case ?
I would have expected it to be = "" ..
type QuotesViewModel() =
inherit ViewModelBase()
let mutable histo = Array.empty
let mutable selectedudl = ""
member x.GetUnderlyings = seq { yield "one"; yield "two"}
member x.SelectedUdl
with get() = selectedudl
and set value =
selectedudl <- value
x.OnPropertyChanged <# x.SelectedUdl #>
x.OnPropertyChanged <# x.SelectedGraph #>
member x.SelectedGraph
with get() =
let graph = asyncquotes.visualizehistoForUdl selectedudl
let host = new System.Windows.Forms.Integration.WindowsFormsHost()
host.Child <- new ChartControl(graph, Dock = DockStyle.Fill)
host

Related

Merge properties of a list to another based on properties objects

I got 2 lists with x objects inside , for example:
data class Model(
var token: String = "",
var id: String = "",
var name: String = "",
var image: Int = 0,
)
array is initialized and filled, the other list has x objects also that contains the objects of the first list but with different values in their properties!
what I want to do is to change the properties of the first array by the second one if they got the same object.name
var arr1 = ArrayList<Model>() // locale
var arr2 = ArrayList<Model>() // from db
the first array I got for example
[Model(name = "David", token = "" , image = 0)]
the second array I got
[Model(name = "David", token = "1asd5asdd851", image = 1)]
How do I make the first array take the missing token?
I tried with .filter{} and with .map{}. groupBy {} for hours because Name is the only properties that are the same but I'm more and more confused.
We can first group the second array by name using associateBy() and then iterate over first array and reassign properties:
val arr2ByName = arr2.associateBy { it.name }
arr1.forEach { item1 ->
arr2ByName[item1.name]?.let { item2 ->
item1.token = item2.token
item1.image = item2.image
}
}
Alternatively, if you don't need to modify items in arr1, but create another array and you can use items from both arr1 and arr2, then it will be much easier:
val arr3 = arr1.map { arr2ByName[it.name] ?: it }
One possible way would be to use fold() as follows:
fun main(args: Array<String>) {
val arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
val mergedModels = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(mergedModels)
}
If you want to reuse arr1 variable then you can do the following (but I would still use the previous option):
fun main(args: Array<String>) {
var arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
arr1 = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(arr1)
}

Compare multiple fields of Object to those in an ArrayList of Objects

I have created a 'SiteObject' which includes the following fields:
data class SiteObject(
//Site entry fields (10 fields)
var siteReference: String = "",
var siteAddress: String = "",
var sitePhoneNumber: String = "",
var siteEmail: String = "",
var invoiceAddress: String = "",
var invoicePhoneNumber: String = "",
var invoiceEmail: String = "",
var website: String = "",
var companyNumber: String = "",
var vatNumber: String = "",
)
I want to filter an ArrayList<SiteObject> (call it allSites) by checking if any of the fields of the objects within the list match those in a specific <SiteObject> (call it currentSite).
So for example, I know how to filter looking at one field:
fun checkIfExistingSite(currentSite: SiteObject) : ArrayList<SiteObject> {
var matchingSites = ArrayList<SiteObject>()
allSites.value?.filter { site ->
site.siteReference.contains(currentSite.siteReference)}?.let { matchingSites.addAll(it)
}
return matchingSites
}
But I am looking for an elegant way to create a list where I compare the matching fields in each of the objects in allSites with the corresponding fields in currentSite..
This will give me a list of sites that may be the same (allowing for differences in the way user inputs data) which I can present to the user to check.
Use equals property of Data Class:
val matchingSites: List<SiteObject> = allSites
.filterNotNull()
.filter { it.equals(currentSite) }
If you are looking for a more loose equlity criteria than the full match of all fields values, I would suggest usage of reflection (note that this approach could have performance penalties):
val memberProperties = SiteObject::class.memberProperties
val minMatchingProperties = 9 //or whatever number that makes sense in you case
val matchingItems = allSites.filter {
memberProperties.atLeast(minMatchingProperties) { property -> property.get(it) == property.get(currentSite) }
}
fun <E> Iterable<E>.atLeast(n: Int, predicate: (E) -> Boolean): Boolean {
val size = count()
return when {
n == 1 -> this.any(predicate)
n == size -> this.all(predicate)
n > size - n + 1 -> this.atLeast(size - n + 1) { !predicate.invoke(it) }
else -> {
var count = 0
for (element in this) {
if (predicate.invoke(element)) count++
if (count >= n) return true
}
return false
}
}
}
you could specify all the fields by which you want to match the currentSite inside the filter predicate:
fun checkIfExistingSite(currentSite: SiteObject) =
allSites.filter {
it.siteAddress == currentSite.siteAddress
|| it.sitePhoneNumber == currentSite.sitePhoneNumber
|| it.siteReference == currentSite.siteReference
}
Long but fast solution because of short circuiting.
If the list is nullable you can transform it to a non nullable list like:
allSites?filter{...}.orEmpty()
// or imho better
allSites.orEmpty().filter{...}

How to get the index of a gson object?

I need to get the index of the array containing the member fileName = "Andres"
data class File(var fileName: String, var _id : String? = null)
data class Files(val files: Array<File>)
val miObjetG = Gson().fromJson(response_files, Files::class.java)
var indice = miObjetG.files.filterIndexed { index, file -> file.fileName == "Andres"}
I think indexOfFirst is what you are looking for:
val index = miObjetG.files.indexOfFirst{ it.fileName == "Andres" }

how to find an index in Arraylist of custom object based on its specific properties in Kotlin?

I have an arraylist of event
var approvedEvents = ArrayList<Event>()
the class of Event is like this
class Event() {
var eventID : String = ""
var createdBy: String = "" // uid of user creator
var creatorFullName: String = ""
var creatorIsVerified : Boolean = false
var creatorProfilePictureImagePath = ""
var createdAt : Date = Calendar.getInstance().time
var hasBeenApproved : Boolean = false
var title : String = ""
var speaker : String? = null
var coordinate : GeoPoint = City.defaultCityCoordinate
var address : String = ""
var city : String = ""
var venue : String = ""
}
so I want to find an index in approvedEvents arraylist that its eventID match selectedEvent.eventID how to do that in Kotlin ? is there specific method that I can use ?
Use indexOfFirst or indexOfLast to find the index of an item in an ArrayList based on your own criteria like below:
val index = approvedEvents.indexOfFirst{
it.eventID == selectedEvent.eventID
}
First of all, you have to override equals function in your Event class like
------
------
var city : String = ""
var venue : String = ""
override fun equals(other: Any?): Boolean{
if(other is Event){
return eventID.equals(other.eventID)
}
return false;
}
}
Now when you want to search for an Event object with eventId in a list, first create a temporary event object with that eventId which you want to search like
val temp=Event()
temp.eventID="102"
and simply get the index
print(events.indexOf(temp))

Deserializing an F# discriminated union with protobuf-net

Using the following SO answer as a guideline: Serializing F# discriminated unions with protobuf
I have put together a way to serialize a simple F# discriminated union. Unfortunately I cannot get it to serialize the second case of the DU without throwing a stackoverflow exception. What am I doing wrong?
CODE
open System
open System.IO
open System.Collections.Generic
open ProtoBuf
[<ProtoContract>]
[<ProtoInclude(100, "Program+DU+Good")>]
[<ProtoInclude(200, "Program+DU+Bad")>]
type DU =
| Good of bool
| Bad of int
with
override this.ToString() =
match this with
| Good i -> i.ToString()
| Bad s -> s.ToString()
[<ProtoContract; Serializable>]
type Person(name:string, age:int, du:DU) =
let mutable name = name
let mutable age = age
let mutable du = du
new() = Person("",0,Good true)
[<ProtoMember(1)>]
member this.Name
with get() = name
and set(v) = name <- v
[<ProtoMember(2)>]
member this.Age
with get() = age
and set(v) = age <- v
[<ProtoMember(3)>]
member this.DU
with get() = du
and set(v) = du <- v
override this.ToString() = this.Name + ", " + this.Age.ToString() + ", " + this.DU.ToString()
[<EntryPoint>]
let main argv =
// typeof vs typedefof ?
ProtoBuf.Meta.RuntimeTypeModel.Default.[typeof<DU>.GetNestedType("Good")].Add("item").UseConstructor <- false
ProtoBuf.Meta.RuntimeTypeModel.Default.[typeof<DU>.GetNestedType("Bad")].Add("item").UseConstructor <- false
//RuntimeTypeModel.Default.[typeof<DU>].CompileInPlace() // doesn't seem to make any difference
let p1 = Person("Sam", 38, Good false)
let p2 = Person("Cand", 34, Bad 99)
let filePath = #"C:\Temp\protocol.bin"
if not (File.Exists filePath) then
let fs = File.Create(filePath)
fs.Close()
use fileStream1 = new System.IO.FileStream(filePath, FileMode.Truncate, FileAccess.Write)
ProtoBuf.Serializer.Serialize<Person>(fileStream1, p2) // p1 does work because it uses the first case of the DU
fileStream1.Close()
use fileStream2 = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read)
let result = ProtoBuf.Serializer.Deserialize<Person>(fileStream2) // stackoverflow exception ONLY for p2
fileStream2.Close()
printfn "%A" result
Console.ReadLine() |> ignore
0 // return an integer exit code