Given I have a map like:
def myMap = [ b : [ c:"X" ] ]
And a string
def key = 'b.c'
I'd like to see my options for using the key to get to the value 'X'.
I have come up with two ways of achieving this myself, but I am not very happy with these solutions:
1) Eval.me("theMap", myMap, "theMap.$key")
2) mayMap."$key.split('\\.')[0]"."$key.split('\\.')[1]"
Anyone has a better way of doing this in Groovy?
A convenient way is to use ConfigObject which implements Map.
def myMap = [b:[c:'X', d: 'Y'], a:[n:[m:[x:'Y']]]] as ConfigObject
def props = myMap.toProperties()
assert props['b.c'] == 'X'
assert props.'b.c' == 'X'
assert props.'a.n.m.x' == 'Y'
Pros:
No more splitting.
No more evaluating.
IMHO its not the ConfigObject, that does the trick, its the Properties (from ConfigObject.toProperties()). Look & try:
def props = new ConfigSlurper().parse("""
b {
c = 'X'
d = 'Y'
}
a {
n {
m {
x:'Y'
}
}
}""")
assert props['b.c'] == 'X'
assert props.'b.c' == 'X'
assert props.'a.n.m.x' == 'Y'
'passed'
Assertion failed:
assert props['b.c'] == 'X'
| | |
| [:] false
[b:[c:X, d:Y], a:[n:[m:[:]]], b.c:[:]]
at ConsoleScript7.run(ConsoleScript7:14)
and I really wish, the ConfigObject could be indexed with such combined keys like above
Related
I am using FsUnit.Xunit. I am getting a failure for the following test case:
[<Fact>]
let ``Initialization of DFF`` () =
dff Seq.empty Seq.empty |> should equal (seq {Zero})
The test failure is:
Message:
FsUnit.Xunit+MatchException : Exception of type 'FsUnit.Xunit+MatchException' was thrown.
Expected: Equals seq [Zero]
Actual: seq [Zero]
Stack Trace:
That.Static[a](a actual, IMatcher`1 matcher)
Signal.Initialization of DFF() line 11
I get the same error if the test is:
[<Fact>]
let ``Initialization of DFF`` () =
dff Seq.empty Seq.empty |> should equal (Seq.singleton Zero)
I have never tested equality of sequences using FsUnit.Xunit, so I am confused what's going on. I'm not even for sure what the failure message is telling me, as it seems to be saying that the expected and actual are the same. I can get this to work fine by converting the sequences to lists, but it would be nice to not have to do that.
Could someone explain what's going on here? It seems I'm not understanding the error message and thus probably something about Equals and comparing sequence values (literals?). Thanks.
Source code to be able to reproduce (I think this is everything):
type Bit =
| Zero
| One
type Signal = seq<Bit>
let Nand a b =
match a, b with
| Zero, Zero -> One
| Zero, One -> One
| One, Zero -> One
| One, One -> Zero
let Not input =
Nand input input
let And a b =
Not (Nand a b)
let Or a b =
Nand (Not a) (Not b)
let private liftToSignal1 op (signal: Signal) : Signal =
Seq.map op signal
let private liftToSignal2 op (signalA: Signal) (signalB: Signal) : Signal =
Seq.map2 op signalA signalB
let Not' = liftToSignal1 Not
let And' = liftToSignal2 And
let Or' = liftToSignal2 Or
let rec dff data clock : Signal =
seq {
yield Zero
yield! Or' (And' data clock)
(And' (dff data clock) (Not' clock))
}
This is an issue with structural vs. referential equality.
In F# seq { 'a' } = seq { 'a' } // false but [ 'a' ] = [ 'a' ] // true due to seq being IEnumerable and not supporting structural equality (or comparison).
Lists (and other F# container-like types) are much more 'intelligent', i.e. they support structural equality / comparison if the contained objects support it:
[ {| foo = StringComparison.Ordinal; bar = Some(1.23) |} ] =
[ {| foo = StringComparison.Ordinal; bar = Some(1.23) |} ] // true
but don't, if they contain anything that doesn't:
[ box(fun() -> 3) ] = [ box(fun() -> 3) ] // false
So, to make the test work, add a List.ofSeq:
dff Seq.empty Seq.empty |> List.ofSeq |> should equal [ Zero ]
I'm a complete beginner to Elm an I'm struggling with types. I've been struggling a lot with types and I couldn't figure out a convenient way of fixing this problem. The piece of code in question is this:
view model =
div []
[ h1 [] [ text "Robot" ]
, input [ onInput SetX, value model.x ] []
, input [ onInput SetY, value model.y ] []
, input [ type_ "Int" , onInput SetCommands, value model.x] []
, button [ onClick ButtonPressed] []
, input [ readonly True ] []
]
X and Y are Ints used in the following function:
execute_orders : Int -> Int -> String -> String -> String -> { x : Int, y : Int, dir : String }
execute_orders x y commands lang dir =
let
moves =
case lang of
"English" ->
"RLF"
"French" ->
"HVG"
"Swedish" ->
"DGT"
_ ->
Debug.todo "No Language Found"
fw =
right 1 moves
directions =
facing dir
rght =
left 1 moves
lft =
slice 1 2 moves
first_move =
left 1 (toUpper commands)
rest =
slice 1 (length commands) (toUpper commands)
in
if first_move == "" then
{ x = x, y = y, dir = fromJust (head directions) }
else if first_move == fw then
if dir == "N" then
execute_orders x (y - 1) rest lang dir
else if dir == "E" then
execute_orders (x + 1) y rest lang dir
else if dir == "S" then
execute_orders x (y + 1) rest lang dir
else
execute_orders (x - 1) y rest lang dir
else if first_move == lft then
execute_orders x y rest lang (fromJust (head (turn_left directions)))
else if first_move == rght then
execute_orders x y rest lang (fromJust (head (turn_right directions)))
else
Debug.todo "branch '_' not implemented"
I need x and y to be Int's but casting them from String results in the Maybe Integer type...
There is no way to simply "cast" a String to an Int because there's no total mapping in that direction. There is, for example, no obvious integer representation for the string "banana". What you are struggling with isn't "types", but different things being different for different reasons, and having to make a decision to consolidate those differences.
String.toInt returns a Maybe Int because it's up to you to decide what to do when there's no reasonable and obvious integer representation for a given string. It's your choice whether you want to just default to 0, -1, or perhaps display the string - instead. These are all reasonable choices for different scenarios, but since String.toInt can't possibly know which scenario you're in, you have to make that decision.
If you simply want to fall back to a default integer, or you're certain that any given string will have a valid integer representation, you can use Maybe.withDefault:
String.toInt "42" |> Maybe.withDefault 0 -- 42
String.toInt "banana" |> Maybe.withDefault 0 -- 0
Or you can use a case expression to do something completely different:
case String.toInt s of
Just n ->
span [] [ text (n + 1 |> String.fromInt) ]
Nothing ->
button [ onClick ... ] [ text "-" ]
Since the HTML input event always deals with strings, you need to parse the string you receive at some point. There are three options that I see.
First, the payload of your event message can be a String, and then you parse that string in your update function.
type Msg
= SetX String
type alias Model =
{ x : Int }
update msg model =
case msg of
SetX xString ->
case String.toInt xString of
Nothing ->
model
Just x ->
{ model | x = x }
A variation of the above would be to store x as a Maybe String on your model if that makes sense, and/or storing some value for tracking an error state if you want to show a message when an invalid value is sent. This is the simplest and most flexible approach.
A second option is to have the payload of your event message be a Maybe Int. Html.Events.onInput is a function which takes a "tagger" function which accepts a String and outputs a message. While you can just give a message constructor that takes a String payload, you can also give a function which does some processing before creating a Msg value.
type Msg
= SetY (Maybe Int)
view model =
input [ type_ "number", onInput (\value -> String.toInt value |> SetY) ] []
The third option is to have the payload of your event message be an Int. This will require you to create your own version of onInput using Html.Events.on. on takes a Json.Decode.Decoder msg instead of the (String -> msg) function that onInput takes. The message will only be produced if the decoder succeeds; that is, events which produce a failed decoder will be ignored. This allows you to handle the case where the parsing fails within the event handler.
type Msg
= SetY Int
view model =
input [ type_ "number", onNumericInput SetY ] []
-- based on https://github.com/elm/html/blob/97f28cb847d816a6684bca3eba21e7dbd705ec4c/src/Html/Events.elm#L115-L122
onNumericInput : (Int -> msg) -> Attribute msg
onNumericInput toMsg =
let
alwaysStop : a -> ( a, Bool )
alwaysStop x =
( x, True )
failIfNothing : Maybe a -> Decode.Decoder a
failIfNothing maybe =
case maybe of
Nothing ->
Decode.fail "Parsing failed"
Just a ->
Decode.succeed a
decoder : Decode.Decoder msg
decoder =
Events.targetValue
|> Decode.map String.toInt
|> Decode.andThen failIfNothing
|> Decode.map toMsg
in
Events.stopPropagationOn "input" (decoder |> Decode.map alwaysStop)
You can see the last two options in a full example at https://ellie-app.com/h6fstFTyjXDa1
Try flow link.
Here's a simple bounded polymorphism example that doesn't work the way I'd expect it to:
// #flow
function thisBreaks<T: 'a' | 'b'>(x: T): T {
if (x === 'a') {
return 'a'
} else {
return 'b'
}
}
function thisWorks<T: 'a' | 'b'>(x: T): T {
return x
}
const a = 'a'
const aPrime: 'a' = thisWorks(a)
const b = 'b'
const bPrime: 'b' = thisWorks(b)
5: return 'a'
^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {
^ some incompatible instantiation of `T`
7: return 'b'
^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {
^ some incompatible instantiation of `T`
I would have expected the first example to work, since e.g. the x === 'a' check could refine T to 'a', right?
This is not possible and shouldn't be possible. Here is an example that shows why:
function test<T: number | string>(x: T): T {
if (typeof x === 'number') {
return 1;
} else {
return 'b'
}
}
test((5: 5));
The function is supposed to return value of type 5, but returns 1 instead.
So, what happens? We have some unknown type T and we know that T <: string | number (T is subtype of string | number). After we refine x, we know that T is a subtype of number. It doesn't mean that T is number. It can be 5, like in the example, or 1 | 2 | 3. Knowing that T is subtype of number is not enough to create a value of T. To do that we need to know lower bound of T, but there is no way to know it.
The last question is: why is you example apparently safe then? It's simple: if T <: 'a', then it can only be 'a' (or empty, but it doesn't really matter). There are no other subtypes of 'a'. So, theoretically, Flow could support that, but its not very practical: if you know that x is 'a', than you can just return x
I need to check that one array of Map contains another
def map1 = [[key1:"value1", key2:"value2"], [key3:"value3", key4:"value4"]]
def map2 = [[key1:"value1", key2:"value2"]]
Currently i have method which find map in array of map and compare them
def "method"(map2){
def map1 = arrayOfmap
def matches = map1.findAll { map2.contains(it) }
assert matches == map2 //return true
}
Now I want to write a method that will search in the array of maps myMap and check that all the values from myMap are find in map1
For example:
I have
def map1 = [[key1:"value1", key2:"value2"], [key3:"value3", key4:"value4"]]
def map2 = [[key1:"value1"]]
I need check that map1 contains map2
Not sure what you mean, but given:
def map1 = [[key1:"value1", key2:"value2"], [key3:"value3", key4:"value4"]]
Assuming you mean that every element in map2 has to occur in one of the maps in map1, you could do something like:
boolean allFoundIn(List<Map> map, List<Map> query) {
query.every { m2 -> map.any { m1 -> m2.every { m2a -> m1[m2a.key] == m2a.value } } }
}
assert allFoundIn(map1, [[key1:'value1']])
assert allFoundIn(map1, [[key3:'value3'], [key2:'value2']])
assert !allFoundIn(map1, [[key1:'value1'], [keyNone:'not found']])
// Multiple values in one map have to all match the same map in the source
assert allFoundIn(map1, [[key1:'value1', key2:'value2']])
assert !allFoundIn(map1, [[key1:'value1', key3:'value3']])
To find that map1 (bit misleading example as map1 is actually a list not a map) contains all the elements from map2 (another list) you can either use the containsAll method, intersect method or subtract all the elements of map1 from map2, note that on partial matching it does not pass, see map3 below
def map1 = [[key1:"value1", key2:"value2"], [key3:"value3", key4:"value4"]]
def map2 = [[key1:"value1", key2:"value2"]]
def map3 = [[key1:"value1"]]
assert map1.containsAll(map2)
assert map1.intersect(map2) == map2
assert map2 - map1 == []
assert !map1.containsAll(map3)
assert !map1.intersect(map3)
assert map3 - map1 != []
This question is related to this previous thread.
I followed Tomas's suggestion using this piece code, and all works fine:
let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color) =
let rec loop (row, col) = seq {
if not (row < 0 || col < 0 || row > MaxLineNumber - 1
|| col > BallsPerLine - 1) then
let ball = grid.[row,col]
match ball with
| Some(ball) ->
if (!ball.visited = false || not <| ball.color.Equals(color)) then
// Not sure what you want here - yield items using 'yield'?
// [row , col]
else
ball.visited := true
yield row, col // Add single item to results
yield! loop(row + 1, col + 1) // Add all generated to results
yield! loop(row - 1, col - 1) // -- || --
| None -> () }
loop(row, col) |> Seq.toList
The code above iterate through an array 2d of "balls" and return a list of index of adjacent balls with the same color.
Now I have to modify the function in way that it returns also a boolean indicating if at least one ball of the list satisfy a certain condition. I changed the code this way but seems that I can't assign a mutable value inside that code:
let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color) : List<int * int> * bool =
let mutable b : bool = false
let rec loop (row, col) = seq {
if not (row < 0 || col < 0 || row > MaxLineNumber - 1
|| col > BallsPerLine - 1) then
let ball = grid.[row,col]
match ball with
| Some(ball) ->
if (ball.visited = true || not <| ball.color.Equals(color)) then
()
else
//HERE's THE PROBLEM
if (ball_satisfy_a_certain_condition) then
b <- true
ball.visited := true
yield row, col // Add single item to results
yield! loop(row + 1, col + 1) // Add all generated to results
yield! loop(row - 1, col - 1) // -- || --
| None -> () }
loop(row, col) |> Seq.toList, b
It seems that a mutable variable can't be acquired by a closure (I don't know what it means).
So I have 2 questions:
why is the above assignment to a mutable variable wrong?
How should I refactor my code to achieve this goal?
In short, you have to use ref variables instead of mutable variables.
While mutable variables are allocated on the stack, ref variables are heap-based. After each time your loop function is invoked, mutable values are wiped out when ref values are still there. Therefore, only ref values are valid to return in GetSameColorNeighs.
This question has been asked many times here. See The mutable variable 'i' is used in an invalid way.? and this blog post for more in-depth discussion.