Velocity Template : Display from nth position of an array - arrays

For customizing app dynamics email templates, we have to use velocity template 1.7
I have a health rule named ab-cd-ef-gh. First two part is constant and the last two part is the name of the microservice. I want to display the part after 'ef'. Please note that the length of the health rule is not fixed, meaning the part starting from 'ef' can have 2 part or 3 part or 5 part depending on the name.
I have used split function to split based on the delimiter '-'.
set ($output=$originalmessage.split('-'))
Output variable has all the parts of the health rule.
Now I want to print from 2nd index of the array, ie from 'ef' till the end of the array. To get the size of the array , i used #set ($outputsize=$output.size()), ie is array.size().
How will print the part starting from 'ef' till the end of the array.
The logic I used was as below.
#set ($start=5)
#foreach ($i in [$start..$outputsize])
${arrays.asList($output).get($i)}
But, I am not getting the output. Please help me to get the service name printed.

In VTL, arrays and lists are equivalent. On both of them you can use .get(i) or [i] to access the ith element, or call the .size() method.
So I guess that
#set ($outputsize = $output.size() - 1)
#set ($start=5)
#foreach ($i in [$start..$outputsize])
$output.get($i)
#end
is enough, as would:
#set ($outputsize = $output.size() - 1)
#set ($start=5)
#foreach ($i in [$start..$outputsize])
$output[$i]
#end

Related

Output $Error using a variable in the array index

Have this code, which takes the errors and output the exceptions.
I want to use a variable in the index of an array, but it does not resolve.
[int32]$ErrorCounter = $Error.Count
$ErrorResponse = $($Error[($ErrorCounter)].Exception)
Write-Host "$A, $B, $ErrorResponse"
This appears in a loop, and the $error contains information I want to parse. So it needs to output the latest $error entry, not the whole $error array.
As Ansgar noted, the most recent error is at index 0. If you want the oldest error message, which is what your original message does, you would need to subtract one from $ErrorCounter since the index is 0 based. Or just use the built-in powershell accessor like $ErrorResponse = $Error[-1].Exception. The -1 starts from the end of the collection instead of the beginning. You can use a negative number up to the size of your $count you computed earlier.

GAMS: Saving outputs generated in a loop to a single .gdx file without overwriting previous entries

I want to have a scenarios of 3 runs in GAMS, where I also want to save each of the 3 randomly selected elements of the set "codes" into a .gdx file, without each entry being overwritten by the next randomly generated output in the loop. How can I prevent this overwritting such that I am able to save each randomly generated output in the loop, in one single output.gdx file? The following is my code so far:
SET
codes /aaa, aab, aac, aad, aae, aaf, aag, aah, aaj, aak, aal/
selected(codes);
$gdxout outputs
loop((1,3),
randnumber = uniformint(1,11);
selected(codes)=ord(codes)=randnumber;
execute_unload 'output.gdx',selected;
display selected;
);
$gdxout
The result of my code above gives me a .gdx file with only 1 entry - the last (3rd) randomly selected element of the set "codes". Some help on this will be deeply appreciated.
You could use an addition "scenario index" to store the results in a parameter while executing the loop and export everything at once at the end like this:
SET
codes /aaa, aab, aac, aad, aae, aaf, aag, aah, aaj, aak, aal/
scenario /1*3/;
scalar
randnumber;
parameter
selected(scenario,codes);
loop(scenario,
randnumber = uniformint(1,11);
selected(scenario,codes)=ord(codes)=randnumber;
);
execute_unload 'output.gdx',selected;
display selected;
I help that helps!
Lutz

Perl array referencing reversing

I am newbie to perl. And have been working with CSV files, JSON strings, arrays and hashes.
I have written this code, but it is giving me error. I want to use $header_copy in foreach loop.
1. my #headers=qw/January February March April May June/;
2. my $header_copy=\#headers;
3. print("$header_copy->[2]"); # Prints "March" Correctly
4. print("$header_copy[2]"); #Gives Error.
Error:
Global symbol "#header_copy" requires explicit package name at line 4
And I want to use $header_copy in for loop: like:
foreach $i ($header_copy){ **code..** }
You are taking the reference of #headers array using \#headers into $header_copy. So, before accessing it, you need to dereference it.
There are two ways(actually more than that) for it:
Using Arrow operator(->) - Most suitable for accesing a single item from arrayref
Using # { } - Suitable for iterating over arrayrefs .
$header_copy[2] will give error because you are accessing an element from arrayref without dereferencing it. The interpreter assumes it as an array #header_copy not an arrayref because the syntax says it.
Below program summarizes both approach:
#!/usr/bin/perl
use strict;
use warnings;
# define # headers
my #headers = qw/January February March April May June/;
# taken refrence of #headers array into $header_copy
my $header_copy = \#headers;
# dereferencing using arrow(->) operator
print $header_copy -> [2],"\n";
# derefrencing for iteration using #{...}
foreach(#{ $header_copy }) {
print $_,"\n";
}
The error 'Global symbol "..." requires explicit package name' is Perl-speak for "you're trying to use an undeclared variable". It even tells you the name of the undeclared variable - in this case it's #header_copy.
And if you look in your code, you'll see there's no declaration for an array called #header_copy. Oh, you have a scalar variable called $header_copy. And that contains a reference to an array (the array #headers). But that has no connection to an array called #header_copy.
So why does Perl think you want to use the array #header_copy? Well in the last line of your code, you use $header_copy[2] - which means "the third element in array #header_copy". And that generates an error because (as I've already pointed out) you don't have that array.
On the previous line you use $header_copy->[2]. And that works fine because ->[...] is the correct way to look up an element in an array that you have a reference to.
The important thing to realise is that $header_copy->[2] and $header_copy[2] mean two completely different things and refer to two completely different variables.
You also ask how you can get back to an array that you have a reference to (this is called "dereferencing"). That is simple. In general you use:
#{ expression that returns an array reference }
So, in your case, that would be:
#{ $header_copy }
But in cases where your expression is a scalar variable, you can simplify it by omitting the braces, so it becomes:
#$header_copy
So you want:
foreach my $i (#$header_copy) {
...
}
# reads data
my #headers=qw/January February March April May June/;
# use a foreach loop and store local copy of item nr in $headeritem_copy
foreach my $headeritem_copy (#headers) {
print("$headeritem_copy\n");
}
my #headers=qw/January February March April May June/;
my $header_copy=\#headers;
print("$header_copy->[2]"); # Prints "March" Correctly
De-reference the particular index
print("#{$header_copy}->[2]"); #Gives Error.

Locating a dynamic string in a text file

Problem:
Hello, I have been struggling recently in my programming endeavours. I have managed to receive the output below from Google Speech to Text, but I cannot figure out how draw data from this block.
Excerpt 1:
[VoiceMain]: Successfully initialized
{"result":[]}
{"result":[{"alternative":[{"transcript":"hello","confidence":0.46152416},{"transcript":"how low"},{"transcript":"how lo"},{"transcript":"how long"},{"transcript":"Polo"}],"final":true}],"result_index":0}
[VoiceMain]: Successfully initialized
{"result":[]}
{"result":[{"alternative":[{"transcript":"hello"},{"transcript":"how long"},{"transcript":"how low"},{"transcript":"howlong"}],"final":true}],"result_index":0}
Objective:
My goal is to extract the string "hello" (without the quotation marks) from the first transcript of each block and set it equal to a variable. The problem arises when I do not know what the phrase will be. Instead of "hello", the phrase may be a string of any length. Even if it is a different string, I would still like to set it to the same variable to which the phrase "hello" would have been set to.
Furthermore, I would like to extract the number after the word "confidence". In this case, it is 0.46152416. Data type does not matter for the confidence variable. The confidence variable appears to be more difficult to extract from the blocks because it may or may not be present. If it is not present, it must be ignored. If it is present however, it must be detected and stored as a variable.
Also please note that this text block is stored within a file named "CurlOutput.txt".
All help or advice related to solving this problem is greatly appreciated.
You could do this with regex, but then I am assuming you will want to use this as a dict later in your code. So here is a python approach to building this result as a dictionary.
import json
with open('CurlOutput.txt') as f:
lines = f.read().splitlines()
flag = '{"result":[]} '
for line in lines: # Loop through each lin in file
if flag in line: # check if this is a line with data on it
results = json.loads(line.replace(flag, ''))['result'] # Load data as a dict
# If you just want to change first index of alternative
# results[0]['alternative'][0]['transcript'] = 'myNewString'
# If you want to check all alternative for confidence and transcript
for result in results[0]['alternative']: # Loop over each alternative
transcript = result['transcript']
confidence = None
if 'confidence' in result:
confidence = result['confidence']
# now do whatever you want with confidence and transcript.

can't read : variable isn't array

I have the following code :
set arr1(a1) t1
set arr2(a2) t2
set l1 {}
lappend l1 arr1
lappend l1 arr2
set arr3(a3) $l1
foreach names [array names arr3] {
set value $arr3($names)
puts "names = $names, value = $value"
foreach ar $value {
if {[array exists $ar]} {
puts "$ar is an array"
foreach {key val} [array get $ar] {
set d1 $ar($key)
puts "ar key = $key value = $val "
}
}
}
}
but when I run the tcl script it fails for the line "set d1 $ar($key)" . The error msg is 'can't read "ar(a1)": variable isn't array' . Can you please suggest what is causing the error and how do I resolve the same.
When you use the syntax $ar($key), you are looking up the key $key in the array ar and returning its value. This is how Tcl is defined to work, it's in the basic language syntax. However, you're using the ar variable to hold a scalar value, not an array (the two are completely separate; arrays aren't values, though lists and dictionaries are). That's why you're getting the error message.
To read from an array that is named in a variable, you either need to use a longer piece of syntax so that you substitute the variable name and then read from that variable (Tcl doesn't do this for you by default, since it's quite dangerous if you're not prepared for it) or you need to make an alias to the named array variable.
Double-Substitution via set
set d1 [set ${ar}($key)]
This works because $… is really (under the hood) an alias for set with a single argument. (Well, except that it doesn't actually call the command; they both call the same C API.) We use the ${...} form to limit what the initial $ uses as its variable name. Be aware that if you put an array element name in ar, you'll get odd results from this.
Aliasing an Array or an Element
upvar 0 $ar theAlias
set d1 $theAlias($key)
The upvar command links variables together, and in particular when used with 0 as its first argument, it aliases variables in the current scope. By establishing theAlias as a fixed alias to the actual array (the one named by $ar), we can then access it just like a normal array. You could also alias directly to an element:
upvar 0 ${ar}($key) theAlias
set d1 $theAlias
Note the same syntax as used with the set solution above; we want the name of the element, not to read it. (Warning: do not alias to elements of the global env array; the code that couples to the system environment variables does not work in a friendly way with aliases.)
The main issue with using upvar is that you can't turn theAlias back into a non-aliased variable (though you can retarget the alias by calling upvar again) other than by throwing away the current stack frame (trivial for a procedure body, not too hard for a namespace via namespace delete, but problematic with the global namespace as deleting that terminates the whole Tcl interpreter).

Resources