How to convert java.lang.String to json in groovy - groovy

My java.lang.String is of form
[[{"ABC":{"total":0,"failed":0,"skipped":0}}], [{"BCD": {"total":0,"failed":0,"skipped":0}}]]
How to convert this to json in groovy?

Parsing json from string with built-in groovy tools is done with groovy.json.JsonSlurper. You can check the documentation at here.
Here's how your example json can be accessed, just like groovy nested map:
def str = '[[{"ABC":{"total":0,"failed":0,"skipped":0}}], [{"BCD": {"total":0,"failed":0,"skipped":0}}]]'
def parser = new JsonSlurper()
def json = parser.parseText(str)
assert json[0][0].ABC.total == 0
assert json[0][0].ABC.failed == 0
assert json[0][0].ABC.skipped == 0
assert json[1][0].BCD.total == 0
assert json[1][0].BCD.failed == 0
assert json[1][0].BCD.skipped == 0

Related

Prep TabPy Script issue - Python

My question is similar to this one: https://community.tableau.com/s/question/0D54T00000C5RcySAF/tableau-prep-builder-20193-including-multiple-functions-from-python-or-r-to-script-step?t=1655319750718&searchQuery
which I found helpful and decided to try to also nest my functions within each-other.
but my script isn't working - I'm not very good at python so I think some syntax might be missing - can anyone provide some guidance?
I also find it very hard to test these things with prep...
import pandas as pd
pd.options.mode.chained_assignment = None # default='warn'
def cc(df):
def cuecompare(df):
print('splitting cue points')
for merlinCue, mpxCue in df.groupby('media.mediaGuid'):
df['merlinCue'].str.split('|')
df['mpxCue'].str.split('|')
print('createNew cue columns')
df['merlinCue_series'] = merlinCue
df['mpxCue_series'] = mpxCue
print('replace nulls/nan with 0')
df['mpxCue_series'] = df['mpxCue_series'].fillna(0)
df['merlinCue_series'] = df['merlinCue_series'].fillna(0)
return df
def custom_compare_eq(series, other):
print('comparing cue data')
length = len(series.values)
for i in range(length):
r1 = eval(str(series.values[i]))
r2 = eval(str(other.values[i]))
if type(r1) != type(r2):
yield False
else:
if type(r1) == int:
yield r1 == r2
elif type(r1) == list:
yield set(r1) == set(r2)
return series, other
df = cuecompare(df)
df = custom_compare_eq(df)
print('moving to output schema')
return df
def get_output_schema():
print('Getting output schema...\n')
return pd.DataFrame({
'mediaGuid': prep_string(),
'match': prep_string()
})
The error that tabpy throws is
2022-06-15,14:52:37 [ERROR] (base_handler.py:base_handler:115): Responding with status=500, message="Error processing script", info="ValueError : Expected a 1D array, got an array with shape (7, 3)", <<call ID: 3e84a296-08a3-459c-aecc-7dce6e3fad3d>>
2022-06-15,14:52:37 [ERROR] (web.py:web:2239): 500 POST /evaluate (127.0.0.1) 14.99ms
Here's a DF input sample:
,media.mediaGuid,merlinCue,mpxCue
0,abc123,1703.0|1144.0|2172.0|735.0,
1,A5EK6URwtnybJwE9iDZBW_HD_1080p_SDR,1120.0|637.0|2026.0|1599.0,
2,A5EK6URwtnybJwDG8wF3Q_HD_1080p_SDR,2663.0|859.0|2281.0|1487.0,
3,A5EK6URwtnyc26LFN6JG1_HD_1080p_SDR,1407.0|1987.0|696.0,
4,A5EK6URwtnyc26LeBYq7U_HD_1080p_SDR,1392.0|1971.0|552.0,
5,A5EK6URwtnyc26KMrR6xN_HD_1080p_SDR,1025.0|1566.0|581.0,
6,A5EK3BMkhJv97MAWFDsnw_HD_1080p_SDR,768.24,768.24
7,A5EK3BMkhJv97MCKo9JDW_HD_1080p_SDR,527,527

Accessing Class attribute from a called function?

Let say I have something like this :
--module1
def called():
if caller.class.attrX == 1 : ...
--module2
class ABC:
attrX = 1
def method():
called()
I want to access caller Class-attribute ?
I know I have to use inspect somehow but can figure how exactly.
python3
Passing a variable to the function is the best (and only?) option.
--module1
def called(attrX):
if attrX == 1 : ...
--module2
class ABC:
self.attrX = 1
def method():
called(self.attrX)
This seems to work for object variable :
/if I can make it work for class-var it will be better/
import inspect
def say(*args, **kwargs) :
obj = inspect.currentframe().f_back.f_locals['self']
if hasattr(obj,'aaa') : print('hasit')
else : print("no")
class ABC:
aaa = 2
def test(self):
say(123)
i.e. if I dont have 'aaa' set in advance :
In [8]: a.test()
no
In [9]: ABC.aaa = 2
In [10]: a.test()
no
In [12]: a.aaa = 3
In [13]: a.test()
hasit

Groovy create list of 2 maps from string

Hi i have this String which contains List of 2 strings. These 2 strings then contain 2 maps.
Example def listStr = '["{"isReal":true,"area":"a"}","{"isRefundable":false,"area":"b"}"]';
How can i get from this string list of 2 maps?
Result [{isReal=true},{isRefundable=false}]
JsonSlurper can do the job for you:
import groovy.json.JsonSlurper
JsonSlurper js = new JsonSlurper()
def listStr = '["{"isReal":true}","{"isRefundable":false}"]'
def res = []
listStr.eachMatch( /"(\{[^\{\}]+\})"/ ){ res << js.parseText( it[ 1 ] ) }
assert [[isReal:true], [isRefundable:false]] == res
If you want to have a map in the output, you can trasnform the res like:
Map map = res.collectEntries{ it }
assert [isReal:true, isRefundable:false] == map

Groovy pointer to list

As I'm totally new to Groovy I have this problem I don't know how to solve:
I wan't to get a new value from a list, which list is depending of the value of the input string:
Simplified Example:
class NewStringValue
{
def getValue (inpList)
{
def list1 = ["L1V1","L1V2","L1V3"];
def list2 = ["L2V1","L2V2","L2V3","L2V4"];
def worklist = Here is my problem, how do I get Worklist to point to the correct list according to the value in InpList, see calling ex. below?
def i = 0;
def j = worklist.size-1;
while (i<=j)
{
// some code.......
newValue = worklist[i];
}
return newValue;}
Example of calling above
value = getValue("list1")
You can use a map, and look up the values based on the key passed in:
class NewStringValue {
def getValue(inpList) {
def lookup = [
list1: ["L1V1","L1V2","L1V3"],
list2: ["L2V1","L2V2","L2V3","L2V4"]
]
def worklist = lookup[inpList]
def newValue = ''
worklist.each {
newValue += it
}
newValue
}
}
new NewStringValue().getValue('list2')

Groovy named parameters cause parameter assignments to switch--any way around this?

Groovy will collect all the named parameters into a map and pass it into a method as the first parameter. This seems neat, but after trying to make it work it seems really unusable.
So the issue is a method like this:
def method(paramMap, specificVar1 = 7, specificVar2 = 14)
when you call this method with something like this:
method(12, extraValue: "hello")
you get pretty much what you expect:
assert 12 == specificVar1
assert 14 == specificVar2
assert [extraValue:"hello"] == paramMap
not bad, makes sense. The problem is, if you assume the Map params are optional then you can end up with values like this:
method(12)
assert paramMap == 12
assert specificVar1 == 7 // default values
assert specificVar2 == 14
That scalar should have gone into specificVar--not the map. If I specifically type the map in the method:
def method(Map paramMap, specificVar1 = 7, specificVar2 = 14)
then method(12, extraValue: "hello") works just as it did before, but method(12) throws a ClassCastException. This just doesn't seem usable. Is there any way to make that Map "sticky" so that it will simply be empty if there are no Map parameters?
Setting default values on parameters create overloaded methods with combinations made from left to right, thus, it is hard to make method(12) and also be able to pass map entries.
Your method def method(paramMap, specificVar1=7, specificVar2=14) will generate the following methods:
Object Maps.method(java.lang.Object)
Object Maps.method(java.lang.Object,java.lang.Object)
Object Maps.method(java.lang.Object,java.lang.Object,java.lang.Object)
And a fully typed method with the map param:
def method3(Map paramMap=[:], Integer specificVar1=7, Integer specificVar2=14) {
}
Will generate the following methods:
Object Maps.method3()
Object Maps.method3(java.util.Map)
Object Maps.method3(java.util.Map,java.lang.Integer)
Object Maps.method3(java.util.Map,java.lang.Integer,java.lang.Integer)
(No suitable method for method(12)).
Also, entries passed to the method will be collected and inserted in the first map parameter. The following method:
def method4(Integer specificVar1=7, Integer specificVar2=14, Map map=[:]) {
Generates:
Object Maps.method4()
Object Maps.method4(java.lang.Integer)
Object Maps.method4(java.lang.Integer,java.lang.Integer)
Object Maps.method4(java.lang.Integer,java.lang.Integer,java.util.Map)
Thus, method4 12, a:'b' fails with:
No signature of method: Maps.method4() is applicable for argument types:
(java.util.LinkedHashMap, java.lang.Integer) values: [[a:b], 12]
So, no, i don't think you can do what you want using maps :-).
Solution 1:
If you are in for a pure dynamic solution, you can use a single map argument:
def method5(Map map) {
def specificVar1 = map.specificVar1 ?: 7
def specificVar2 = map.specificVar2 ?: 14
}
Solution 2 (updated):
You can create a class to represent the parameters. Using a map to be coerced into the object is statically compilable and a syntatic sugar for it.
#groovy.transform.CompileStatic
class Maps {
def method6(Foo foo) { "$foo.params, $foo.specificVar1, $foo.specificVar2" }
def method6(Map map) { method6 map as Foo }
static main(args) {
def maps = new Maps()
assert maps.method6(params: [a: 'b', c: 'd'], specificVar1: 40) ==
"[a:b, c:d], 40, 14"
assert maps.method6(new Foo(params: [a: 'b', c: 'd'], specificVar2: 21)) ==
"[a:b, c:d], 7, 21"
}
}
class Foo {
def specificVar1 = 7, specificVar2 = 14, params = [:]
}
Solution 3:
An overloaded method.
def method6(Map paramMap, Integer specificVar1=7, Integer specificVar2=14) {
"$paramMap, $specificVar1, $specificVar2"
}
def method6(Integer specificVar1=7, Integer specificVar2=14) {
method6 [:], specificVar1, specificVar2
}
assert method6( 12 ) == "[:], 12, 14"
assert method6( ) == "[:], 7, 14"
assert method6( a:'b', 18 ) == "[a:b], 18, 14"
assert method6( 18, a:'b', 27 ) == "[a:b], 18, 27"
assert method6( 90, 100 ) == "[:], 90, 100"
assert method6( a:'b', 140, c:'d' ) == "[a:b, c:d], 140, 14"
The map version method can't have a default parameter, otherwise both methods will generate a parameterless method6 and those will conflict.

Resources