Obtaining the value of a key inside a dictionary - tcl

I currently have something like this
(Desktop) 1 % dict set mymap keyA "KeyA value"
keyA {KeyA value}
(Desktop) 2 % dict set mymap keyB "KeyB value"
keyA {KeyA value} keyB {KeyB value}
(Desktop) 3 % dict get $mymap keyB
KeyB value
(Desktop) 4 % dict set mymap keyC {KeyD "keyD Value"}
keyA {KeyA value} keyB {KeyB value} keyC {KeyD "keyD Value"}
(Desktop) 5 % dict get $mymap keyC.keyD
key "keyC.keyD" not known in dictionary
The keyC basically contains another dictionary. That dictionary has a key called keyD with a value "KeyD Value" . How can i obtain the value of the keyD ? I tried keyC.keyD
Update :
The reason I need this is because I have something like this
(Desktop) 20 % puts $mymap
{$schema} http://json-schema.org/draft-04/schema# title Product description {A product from Acme's catalog} type object properties {id {description {The unique identifier for a product} type integer}} required id
And I require the value of description from within id. The above is a json object converted to a dictionary

Just put the keys one after each other as mentioned in the docs:
dict get $mymap keyC KeyD
But do be careful about the case, keyD and KeyD are not the same thing.

Related

Extract and explode inner nested element as rows from string nested structure

I would like to explode a column to rows in a dataframe on pyspark hive.
There are two columns in the dataframe.
The column "business_id" is a string.
The column "sports_info" is a struct type, each element value is an array of string.
Data:
business_id sports_info
"abc-123" {"sports_type":
["{sport_name:most_recent,
sport_events:[{sport_id:568, val:10.827},{id:171,score:8.61}]}"
]
}
I need to get a dataframe like:
business_id. sport_id
"abc-123" 568
"abc-123" 171
I defined:
schema = StructType([ \
StructField("sports_type",ArrayType(),True)
])
df = spark.createDataFrame(data=data, schema=schema) # I am not sure how to create the df
df.printSchema()
df.show(truncate=False)
def get_ids(val):
sports_type = 'sports_type'
sport_events = 'sport_events'
sport_id = 'sport_id'
sport_ids_vals = eval(val.sports_type[0])['sport_events']
ids = [s['sport_id'] for s in sport_ids_scores]
return ids
df2 = df.withColumn('sport_new', F.udf(lambda x: get_ids(x),
ArrayType(ArrayType(StringType())))('sports_info'))
How could I create the df and extract/explode the inner nested elements?
df2 = df.withColumn('sport_new', expr("transform (sports_type, x -> regexp_extract( x, 'sport_id:([0-9]+)',1))")).show()
Explained:
expr( #use a SQL expression, only way to access transform (pre spark 3)
"transform ( # run a SQL function on an array
sports_type, # declare column to use
x # declare the name of the variable to use for each element in the array
-> # Start writing SQL code to run on each element in the array
regexp_extract( # user SQL regex functions to pull out from the string
x, #string to run regex on
'sport_id:([0-9]+)',1))" # find sport_id and capture the number following it.
)
THis will likely run faster than a UDF as it can be vectorized.

How to get the nested array value?

I have a nested array as below:
array set arrayA {0 {1 a 2 b 3 c 4 d}}
If I want to update the arrayA like this:
set arrayA(0)(1) "update"
It can't get {0 {1 update 2 b...}}, how to get it? Thanks!
Tcl arrays can't be nested that way, but your code is still valid. In arrayA, the value of element 0 is a dict, so you can get and set members in it with dict operations:
% dict get $arrayA(0) 1
a
% dict set arrayA(0) 1 update
1 update 2 b 3 c 4 d
Another alternative is to use composite names for the array members:
array set arrayA {0.1 a 0.2 b 0.3 c 0.4 d 1.1 aa 1.2 ab}
and access them with arrayA(0.1), arrayA(0.$foo) etc. Which separator character to use is mostly a question of preference, the only rule is that the name must be a proper list. You don't even really need a separator, as long as you always keep the element name in a variable:
% array set arrayA {{0 1} a {0 2} b}
% set idx {0 1}
0 1
% set arrayA($idx)
a
Documentation:
array,
dict

assign a key value list to an array in Tcl

I have a list that is a key value paired list. Something like the following
key1 value1 key2 value2 key3 value3
I would like to map this to an array or a dictionary.
Currently, my code looks like this
for {set i 0} {$i < [llength $list]} {incr i} {
if {[expr {fmod($i,2)}] == 0} {
set key [lindex $list $i]
} else {
set v_array(${key}) [lindex $list $i]
}
}
In perl, I know this can be assigned into a key value dictionary in one pass. Is there such simpler method in Tcl?
You can create an array in one line (I'm using one line to define the list):
% set list [list key1 value1 key2 value2 key3 value3]
key1 value1 key2 value2 key3 value3
% array set v_array $list
And if you want to check the contents, you can use parray (Tcl 8.5 and later):
% parray v_array
v_array(key1) = value1
v_array(key2) = value2
v_array(key3) = value3
And the documentation for the other array commands can be found here with examples for each.
If you somehow cannot avoid a loop, then using foreach would be easier (be sure the list has an even number of elements):
foreach {a b} $list {
set v_array($a) $b
}
(Here foreach is taking the elements in $list two at a time and assign them to a and b)
You can use dict command for creating/manipulating dictionaries in Tcl.
% set mydict [dict create key1 value1 key2 value2 key3 value3]
key1 value1 key2 value2 key3 value3
% dict get $mydict
key1 value1 key2 value2 key3 value3
% dict get $mydict key3
value3
% dict get $mydict key1
value1
%
Even without the dict create command, you can straightway fetch/access the keys and values even from a list as long as it is in key-value form. i.e. even number of elements.
For example,
% set mylist {key1 value1 key2 value2 key3 value3}
key1 value1 key2 value2 key3 value3
% dict get $mylist key2
value2
As you can notice, I have not used dict create command here , but still able to access the dictionary items.
Reference : dict
Easiest solution:
set mylist {key1 value1 key2 value2 key3 value3}
array set arr $mylist
Thats it.
Now, do a parray to check.
file: t3
#
set list [list key1 value1 key2 value2 key3 value3]
array set arr $list
parray arr
#
Execute the file: tclsh t3
arr(key1) = value1
arr(key2) = value2
arr(key3) = value3

How to encode tuple to JSON in elm

I have tuple of (String,Bool) that need to be encoded to JSON Array in elm.
This below link is useful for the primitive types and other list, array and object. But I need to encode tuple2.
Refer : http://package.elm-lang.org/packages/elm-lang/core/4.0.3/Json-Encode#Value
I tried different approach like encoding tuple with toString function.
It does not gives me JSON Array instead it produces String as below "(\"r"\,False)".
JSON.Decoder expecting the input paramater to decode as below snippet.
decodeString (tuple2 (,) float float) "[3,4]"
Refer : http://package.elm-lang.org/packages/elm-lang/core/4.0.3/Json-Decode
Q : When there is decode function available for tuple2, why encode function is missing it.
You can build a generalized tuple size 2 encoder like this:
import Json.Encode exposing (..)
tuple2Encoder : (a -> Value) -> (b -> Value) -> (a, b) -> Value
tuple2Encoder enc1 enc2 (val1, val2) =
list [ enc1 val1, enc2 val2 ]
Then you can call it like this, passing the types of encoders you want to use for each slot:
tuple2Encoder string bool ("r", False)
In elm 0.19 https://package.elm-lang.org/packages/elm/json/latest/Json-Encode a generalized tuple 2 encoder would be
import Json.Encode exposing (list, Value)
tuple2Encoder : ( a -> Value ) -> ( b -> Value ) -> ( a, b ) -> Value
tuple2Encoder enc1 enc2 ( val1, val2 ) =
list identity [ enc1 val1, enc2 val2 ]
Usage:
encode 0 <| tuple2Encoder string int ("1",2)

Is there a way to print array in order with entries entered in that [TCL]

I have an array in Tcl, say
set count(a) b
set count(b) b
set count(c) b
set count(e) b
set count(d) b
set count(z) b
set count(m) b
When I print this I get output
array names count
d m e a z b c
Is there a way I can get the same order in which I have written the array?
Use a dict instead (mostly the same thing, just another syntax):
dict set count a b
dict set count b b
dict set count c b
dict set count e b
dict set count d b
dict set count z b
dict set count m b
The following prints the keys in insertion order
% dict keys $count
a b c e d z m
If you want to have it both ways, assign to the dictionary and recreate an array when desired using
array unset countArray
array set countArray $count
dict was added in Tcl 8.5. While an array never preserves insertion order for its elements, original insertion order is kept for dict elements even after later assignments.
Dictionaries and arrays are both implemented as hash tables and have some overlap in functionality. However, arrays are primarily containers for variables and allow elements to be individually traced. Dictionaries are containers of values, and can be interchanged with other kinds of data (the dict command ensemble can only use even-sized proper lists).
Documentation: array, dict
Based on the Tcl wiki you can't do it
Array keys are not ordered. It isn't straight-forward to get values out of an array in the same order that they were set. One common alternative is to get the names and then order them. In contrast, values in a dict are ordered.
dict in tcl8.5 is recommended. This is how you can do it with an array though:
array set foo {}
set fooOrder [list]
trace variable foo w bar
proc bar {args} {
global fooOrder
lappend fooOrder [lindex $args 1]
}
set foo(a) 10
set foo(c) 20
set foo(b) 30
puts "Default behaviour..."
puts [parray foo]
puts "Maintaining the order..."
foreach key $fooOrder {
puts "foo($key) = $foo($key)"
}
Output:
sharad#ss:~$ tclsh my.tcl
Default behaviour...
foo(a) = 10
foo(b) = 30
foo(c) = 20
Maintaining the order...
foo(a) = 10
foo(c) = 20
foo(b) = 30
sharad#ss:~$