Is there a terser way to declare and initialize a dictionary in F#?
let grid = Map.empty
.Add(0, true).Add(1, true).Add(2, true)
.Add(3, true).Add(4, false).Add(5, true)
.Add(6, true).Add(7, true).Add(8, true)
I use:
[0, true
1, false
2, true]
|> Map.ofList
#CaringDev's answer is good, but there's yet another consideration.
The elements of the tuple have key/value relation, so for best clarity I use the following definition:
let (=>) x y = x,y
This lets me write a very readable, self-documented code like this:
let myValue1 =
Map [
0 => true
1 => false
2 => false
]
Also, let makeMap x = new Map<_,_>(x) lets you write the code in another style, depending on your team's coding conventions:
let myValue2 =
[
0 => true
1 => false
2 => false
] |> makeMap
Related
I want to return every value up to and including some key.
Whilst I could generate every such key and chuck them all into the Get, I suspect this will inefficiently search for the value of every key.
Inspired by this answer, I have come up with the following
let getAllUpTo key (frame:Frame<'key,'col>) : Frame<'key, 'col> =
let endRng = frame.RowIndex.Locate key
let startRng = frame.RowIndex.KeyRange |> fst |> frame.RowIndex.Locate
let fixedRange = RangeRestriction.Fixed (startRng, endRng)
frame.GetAddressRange fixedRange
Is there a built in method for doing this efficiently?
If you want to access a sub-range of a data frame with a specified starting/ending key, you can do this using the df.Rows.[ ... ] indexer. Say we have some data indexed by (sorted) dates:
let s1 = series [
let rnd = Random()
for d in 0 .. 365 ->
DateTime(2020, 1, 1).AddDays(float d) => rnd.Next() ]
let df = frame [ "S1" => s1 ]
To get a part of the data frame starting/ending on a specific date, you can use:
// Get all rows from 1 June (inclusive)
df.Rows.[DateTime(2020, 6, 1) ..]
// Get all rows until 1 June (inclusive)
df.Rows.[.. DateTime(2020, 6, 1)]
The API you are using is essentially what this does under the cover - but you are using a very low-level operations that you do not typically need to use in user code.
So I am trying to edit my config list where it has to edit robbed to true when entity is equal to entity in the list (entities get generated when my script is starting)
Config file
Config.location = {
[1] = {
x = 24.39,
y = -1345.776,
z = 29.49,
h = 267.58,
robbed = false,
entity = nil
},
[2] = {
x = -47.7546,
y = -1759.276,
z = 29.421,
h = 48.035,
robbed = false,
entity = nil
},
}
So this list gets loaded - When [1] has been robbed it should change robbed in [1] if the entity matches.
I would imagine i should do a for loop but i'm still clueless.
As Config.list is a sequence with positive integer keys starting from 1 you can conveniently use the iparis iterator in combination with a generic for loop to check every entry in your list.
for i,v in ipairs(Config.location) do
v.robbed = v.entity == someOtherEntity and true or false
end
Of course your entity entries shouldn't be nil as this wouldn't make sense.
I'm working on a game where a bunch of characters will be generated on the fly, based on some constraints defined either in the project or externally via mod files. I am using MoonSharp Lua (5.2) interpreter for interfacing with my C# code, and Lua tables to store the constraint presets. As an example:
require "Defaults"
AgePresets = {}
-- Single value
AgePresets.Newborn = 0
-- Simple ranges
AgePresets.Default = defaultAgeRange --referring to the Defaults require
AgePresets.Child = {1, 12}
AgePresets.Teenager = {13, 19}
AgePresets.YoungAdult = {20, 29}
AgePresets.Adult = {30, 40}
AgePresets.MiddleAge = {40, 60}
AgePresets.Senior = {61, 80}
AgePresets.Elder = {81, 99}
AgePresets.Methuselah = {100, 150}
AgePresets.Methuselah2 = {150, 200}
-- Weighted ranges // again referring to previously defined elements to keep things concise
AgePresets.Tween = {
{weight = 1, minmax = AgePresets.Teenager },
{weight = 1, minmax = AgePresets.YoungAdult }
}
This works fine, but from an end-user point of view, there's a lot of unnecessary typing involved. We are clearly working on AgePresets here but it is still mentioned as a prefix before every member name.
I could of course define AgePresets as an array, like AgePresets = { Child = {}, Teenager = {} } but the problem with that is then I cannot refer to previously defined elements in the array.
This doesn't work:
AgePresets = {
Child = {1,12},
RefToChild = Child, //attempt to index a nil value exception
Teen = {13,19}
}
What I ideally want to achieve is a clean, concise way for users to enter this data in, like in the first example but without having to put AgePresets. prefix before everything. How do I go about declaring a scope in a file such that all succeeding members defined in the file will be within that scope, while maintaining the ability to refer to other members defined previously in the scope?
AgePresets = setmetatable({}, {__index = _G})
do
local _ENV = AgePresets
Newborn = 0
Child = {1,12}
RefToChild = Child -- this ref is Ok
Teen = {13,19}
YoungAdult = {20,29}
Tween = {
{weight = 1, minmax = Teen },
{weight = 1, minmax = YoungAdult }
}
rnd = math.random(10) -- global functions are available here
end
setmetatable(AgePresets, nil)
You can mix the two styles: table constructor for fields that don't need to reference variables that aren't in scope yet, followed by assignment statements for the rest.
I would do that unless the order of the fields in the code significantly enhanced comprehension.
I've tried Chart.WithSize and displayZoomButtons = true in the FSLab tutorial, but nothing seems to change the output.
Same thing in other projects using XPlot.GoogleCharts directly.
Am I missing something?
Download Plotly 1.4.2 from nuget and replace the dlls in the FSLab packages directory for XPlotly (see Plotting with Xplotly Q). Then you can use Xplotly's controls to zoom in and out, save the chart, etc. For example:
#load #"..\..\FSLAB\packages\FsLab\FsLab.fsx"
open XPlot.Plotly
open XPlot.Plotly.Graph
open XPlot.Plotly.Html
//open XPlot.GoogleCharts
let layout = Layout(title = "Basic Bar Chart")
["giraffes", 20; "orangutans", 14; "monkeys", 23]
|> Chart.Bar
|> Chart.WithLayout layout
|> Chart.WithHeight 400
|> Chart.WithWidth 700
|> Chart.Show
Very barebones charting solution using Plotly (and it works):
open Newtonsoft.Json
let html = """<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv" style="width: 100%; height: 100%;"></div>
<script>
var data = __DATA__;
var layout = __LAYOUT__;
Plotly.newPlot('myDiv', data, layout);
</script>
</body>"""
let (=>) k v = k, (v:>obj)
let doPlot data layout =
let data = JsonConvert.SerializeObject data
let layout = JsonConvert.SerializeObject layout
let path = Path.GetTempPath() + DateTime.Now.Ticks.ToString() + ".html"
File.WriteAllText(path, html.Replace("__DATA__", data).Replace("__LAYOUT__", layout))
System.Diagnostics.Process.Start(path)
let layout =
[ "title" => "Plot"
"xaxis" => dict [
"title" => "Ticks"
"showgrid" => false
"zeroline" => false
]
"yaxis" => dict [
"title" => "Price"
"showline" => false
]
] |> dict
let data = [
dict [ "x" => [1999; 2000; 2001; 2002]
"y" => [16; 5; 11; 9]
]
]
doPlot data layout
Let's say I have an array like so:
[
["required": true],
["required": true],
["required": false],
["required": false],
["required": false],
["required": false],
["required": false]
]
I want to insert a new element into this array at the index where required first equals false (at position 2). I'm sure I could determine this using a basic for-each loop, e.g.:
var idx = 0
for (i, el) in myArray.enumerate() {
if el["required"] == false {
idx = i
break
}
}
But this doesn't seem very Swift-like. Is there a cleaner (i.e. less code) way of doing this in Swift 2? Perhaps something using filter or map?
How about this:
let idx = myArray.indexOf({$0["required"] == false})
Swift 3:
let idx = myArray.index(where: { $0["required"] == false })
let required = array.filter { $0["required"] == true }
let notRequired = array.filter { $0["required"] == false }
let result = required + [["required": true]] + notRequired