"first part" &&&& fun _ ->
let ident
"second part" &&&& fun _ ->
ident ....
I need to use variable "ident".
I just need to pass value of variable from first part of test to second one...
I want to ask you if there is any easy way how to define and use global variable or even if you have better (and easy) idea of doing that
Keep in mind, please, that I am a beginner, so I would prefer easier ones.
Global variables will often make your code difficult to work with - particularly if they are mutable.
Instead, consider returning the values you need to keep track of as composite values. An easy data type to start with would be a tuple:
let ``first part`` id =
let someOtherValue = "Foo"
someOtherValue, id + 1
This function takes an int (the current ID) as input, and returns string * int (a tuple where the first element is a string, and the second element and int) as output.
You can call it like this:
> let other, newId = ``first part`` 42;;
val other : string = "Foo"
val newId : int = 43
Notice that you can use pattern matching to immediately destructure the values into two named symbols: other and newId.
Your second function could also take an ID as input:
let ``second part`` id otherArgument =
// use id here, if you need it
"Bar"
You can call it like this, with the newId value from above:
> let result = ``second part`` newId "Baz";;
val result : string = "Bar"
If you find yourself doing this a lot, you can define a record for the purpose:
type Identifiable<'a> = { Id : int; Value : 'a }
Now you can begin to define higher-order functions to deal with such a type, such as e.g. a map function:
module Identifiable =
let map f x = { Id = x.Id; Value = f x.Value }
// Other functions go here...
This is a function that maps the Value of an Identifiable from one value to another, but preserves the identity.
Here's a simple example of using it:
> let original = { Id = 42; Value = "1337" };;
val original : Identifiable<string> = {Id = 42;
Value = "1337";}
> let result' = original |> Identifiable.map System.Int32.Parse;;
val result' : Identifiable<int> = {Id = 42;
Value = 1337;}
As you can see, it preserves the value 42, but changes the Value from a string to an int.
You can still change the ID explicitly, if you want to do that:
> let result'' = { result' with Id = 7 };;
val result'' : Identifiable<int> = {Id = 7;
Value = 1337;}
Since this was getting out of hand for comments this is how I would do it for an example
let mutable t = 0
let first =
t <- 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2
In some cases you have to use a ref:
let t = ref 0
let first =
t := 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2 -
// you use "!t" to get the value
If you define ident at the top of your file like this :
let ident = "foo"
// rest of your code using ident
ident are global and you can use in the next part of your file.
EDIT :
If ident wil change in the next part of your code, use this :
let ident = ref "foo"
Related
Is there an easier approach to convert an Intellij IDEA environment variable into a list of Tuples?
My environment variable for Intellij is
GROCERY_LIST=[("egg", "dairy"),("chicken", "meat"),("apple", "fruit")]
The environment variable gets accessed into Kotlin file as String.
val g_list = System.getenv("GROCERY_LIST")
Ideally I'd like to iterate over g_list, first element being ("egg", "dairy") and so on.
And then ("egg", "dairy") is a tuple/pair
I have tried to split g_list by comma that's NOT inside quotes i.e
val splitted_list = g_list.split(",(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*\$)".toRegex()).toTypedArray()
this gives me first element as [("egg", second element as "dairy")] and so on.
Also created a data class and tried to map the string into data class using jacksonObjectMapper following this link:
val mapper = jacksonObjectMapper()
val g_list = System.getenv("GROCERY_LIST")
val myList: List<Shopping> = mapper.readValue(g_list)
data class Shopping(val a: String, val b: String)
You can create a regular expression to match all strings in your environmental variable.
Regex::findAll()
Then loop through the strings while creating a list of Shopping objects.
// Raw data set.
val groceryList: String = "[(\"egg\", \"dairy\"),(\"chicken\", \"meat\"),(\"apple\", \"fruit\")]"
// Build regular expression.
val regex = Regex("\"([\\s\\S]+?)\"")
val matchResult = regex.findAll(groceryList)
val iterator = matchResult.iterator()
// Create a List of `Shopping` objects.
var first: String = "";
var second: String = "";
val shoppingList = mutableListOf<Shopping>()
var i = 0;
while (iterator.hasNext()) {
val value = iterator.next().value;
if (i % 2 == 0) {
first = value;
} else {
second = value;
shoppingList.add(Shopping(first, second))
first = ""
second = ""
}
i++
}
// Print Shopping List.
for (s in shoppingList) {
println(s)
}
// Output.
/*
Shopping(a="egg", b="dairy")
Shopping(a="chicken", b="meat")
Shopping(a="apple", b="fruit")
*/
data class Shopping(val a: String, val b: String)
Never a good idea to use regex to match parenthesis.
I would suggest a step-by-step approach:
You could first match the name and the value by
(\w+)=(.*)
There you get the name in group 1 and the value in group 2 without caring about any subsequent = characters that might appear in the value.
If you then want to split the value, I would get rid of start and end parenthesis first by matching by
(?<=\[\().*(?=\)\])
(or simply cut off the first and last two characters of the string, if it is always given it starts with [( and ends in )])
Then get the single list entries from splitting by
\),\(
(take care that the split operation also takes a regex, so you have to escape it)
And for each list entry you could split that simply by
,\s*
or, if you want the quote character to be removed, use a match with
\"(.*)\",\s*\"(.*)\"
where group 1 contains the key (left of equals sign) and group 2 the value (right of equals sign)
I have a class called Person
data class Person(
val id: Int,
val name: String
)
data class IDs(
val id : Int,
val active : Boolean )
and an array list that has numbers of ids and another list of Persons
val myStu = listOf<Person>(Person(1, "Name_1"), Person(2, "Name_2"), Person(3, "Name_3"))
var ids = listOf<IDs>(IDs(1,false),IDs(2,true),IDs(3,true))
var newIds = listOf<Int>(2,3,4,6)
First I want to apply two actions to the myStu, first is to have a list that include all the items from myStu that his id matches the id in the IDS and only if the active is true
myStu or the new list will have the values
Person(2, "Name_2"), Person(3, "Name_3"))
Then do action two , I need to add a new item to the new list that their id does not exist in the newIds , in another word we will add a new person Person(4,"None") and (6,"None) , 4 and 6 values come from newIds list
the final output will be :
id= 2 name = "Name_2", id= 3 name = "Name_3", id= 4 name = "None" , id =6 name="None"
I want to write the code with filter , I failed with first step because I don't know how to use contains() with the list inside the filter
val newArr = myStu.filter {
ids.contains(it.id)
}
The "easiest" way of doing that would be to use filter directly, there's no need for contains. If we were to use contains, then we would need to also search for which element contained the id, in order to get the status. We can just do a .any() to do both at the same time.
V1
val activeStu = myStu.filter { person -> ids.any { it.id == person.id && it.active } }
val result = newIds.map { newId ->
activeStu.find { it.id == newId } ?: Person(id = newId, name = "None")
}
Another method, that might work a bit better if we have big lists, would be to first transform the IDs list into a map. That way the second part of our code is a bit more efficient, since there is no search involved.
V2
val idsMap = ids.associate { it.id to it.active }
val activeStu = myStu.filter { idsMap[it.id] ?: false }
//the creation of the result list is the same
Version without creating 2 new lists. This works, but it might be quite ineficient processing wise, and also harder to understand what is going on IMO.
V3
val result = newIds.map { newId ->
//try to find an IDs with the current newId and status as true
when (ids.find { it.id == newId }?.active) {
//if found, then find the corresponding Person
true -> myStu.find { it.id == newId } ?: Person(newId, "None") // if this happens, it means that an IDs with status true existed and no Person had that id. Not sure what you want in this scenario, this version creates one of the "none" persons.
//if not found, then create a new one
else -> Person(newId, "None")
}
}
Note: depending on what version of kotlin you have, you might have to change the when statement to this:
when (ids.find { it.id == newId }?.active == true)
Since I think I remember that null didn't used to be treated as false in old versions (I've run this with version 1.4.20).
Btw, you can also use this version with the idsMap from V2, just replace the when(...) with when(idsMap[newId] or when(idsMap[newId] == true) depending on the kotlin version.
type MyType = {a:int; b:int};;
let test = [{a=5;b=10}; {a=10;b=100}; {a=200; b=500}; {a=100; b=2}];;
I would like to create a function which will sum up a and b in such a way it will display
Sum of a : 315
Sum of b : 612
I think I have to use a recursive function. Here is my attempt :
let my_func record =
let adds = [] in
let rec add_func = match adds with
| [] -> record.a::adds; record.b::adds
| _ -> s + add_func(e::r)
add_func test;;
This function doesn't seem to work at all. Is there a right way to do such function?
OK, you know exactly what you're doing, you just need one suggestion I think.
Assume your function is named sumab and returns a pair of ints. Then the key expression in your recursive function will be something like this:
| { a = ha; b = hb; } :: t ->
let (a, b) = sumab t in (ha + a, hb + b)
I'm searching for an existing solution to serialize records to query strings but found nothing. I know about F#'s pretty printing, but I have no idea how to access it manually.
In common I want something like this:
type Person = {first:string; last:string}
type Group = {name:string; size:int}
let person = {first="Mary"; last="Smith"}
let personQueryString = Something.toQueryString person
let group = {name="Full"; size=345}
let groupQueryString = Something.toQueryString group
where
personQueryString -> "first=Mary&last=Smith"
groupQueryString -> "name=Full&size=345"
I don't think such a function exists, but you can write one that uses Reflection:
open System.Reflection
module Something =
let toQueryString x =
let formatElement (pi : PropertyInfo) =
sprintf "%s=%O" pi.Name <| pi.GetValue x
x.GetType().GetProperties()
|> Array.map formatElement
|> String.concat "&"
Since it uses Reflection, it's not as efficient as specialised functions that know about the types in advance, so whether or not this is sufficient for your needs, only you know.
It produces the desired result, though:
> let person = {first="Mary"; last="Smith"};;
val person : Person = {first = "Mary";
last = "Smith";}
> let personQueryString = Something.toQueryString person;;
val personQueryString : string = "first=Mary&last=Smith"
> let group = {name="Full"; size=345};;
val group : Group = {name = "Full";
size = 345;}
> let groupQueryString = Something.toQueryString group;;
val groupQueryString : string = "name=Full&size=345"
Given a number of functions test1, test2, ... belonging to a module:
module Checks =
let test1 x = ...
let test2 x = ...
...
how can the (?) operator be used to give access to both the function name and the function itself? The result should look like:
let name, func = Checks?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to be pure)
You cannot use the ? operator to access functions in a module, because the construct Checks?test1 is not syntactically correct (this would be translated to (?) Checks "test" and you cannot use module names as values).
However, it should be possible to do this for members of a type using an instance of the object (e.g. obj?test). Alternatively you could write a "fake" object instance (that knows the name of the module). The implementation of ? would then look for the module and search static members in the module.
The simplest implementation (of the first case) would look like this:
let (?) obj s =
let memb = obj.GetType().GetMethod(s)
// Return name and a function that runs the method
s, (fun args -> memb.Invoke(obj, args))
// Type that contains tests as members
type Check() =
member x.test1 () = 32
// We need to create instance in order to use '?'
let ch = Check()
let s,f = ch?test1
// Function 'f' takes array of objects as an argument and
// returns object, so the call is not as elegant as it could be
let n = ((f [| |]) :?> int)
You could also add some wrapping to make the function 'f' a little bit nicer, but I hope this demonstrates the idea. Unfortunately, this cannot work for modules.
Here's some sample code that shows off some of this. I use D as the 'dynamic' access of the Checks module plus function name.
module Checks =
let test1(x) = printfn "test1 %d" x
let test2(x,y) = printfn "test2 %s %d" x y
type MyDynamic() = class end
let D = new MyDynamic()
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) =
let a = md.GetType().Assembly
let t = a.GetType("Program+Checks")
let m = t.GetMethod(fname)
let f arg =
let at = arg.GetType()
let fsharpArgs =
if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg)
else
[| box arg |]
unbox(m.Invoke(null, fsharpArgs))
fname, f
let Main() =
let x = 42
let s = "foo"
let name, func = D?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x))
let name, func = D?test2
assert(name = "test2")
assert(func(s,x) = Checks.test2(s,x))
System.Console.ReadKey()
Main()