v1- old var, v2 - new var.. Currently if anyone sets v1 it will error out so I am making it backward compataible. So if old var v1 is defined anywhere I want to make those 2 variables the same i.e v2 = v1 (Also value of v1 should be in v2)
set v1 test
For this I have a hash with old and new names
set oldvars(v1) v2
foreach ele [array names oldvars] {
if {([info exists ele] || $ele == "") && $oldvars($ele)!= ""} {
o2n $ele $oldvars($ele) //o2n is a proc defined below
}
}
proc o2n {gvar gval}
global v1
puts "gvar is $gvar, gval is $gval" //prints gvar - v1 and gval - v2
set $gval [set $$gvar] **//Error - Cant read $v1 no such variable. Above line does print gvar = v1 so $$gvar should be $v1 =test**
puts "$gval [set $gvar]" // Has the value of v1 i.e test
}
puts "v2 is $v2" **: Error : Can't read v2 no such variable**
If we assume
set a1 1
set b1 2
set c1 3
set oldvars(a1) a2
set oldvars(b1) b2
set oldvars(c1) c2
All you have to do to copy values from x1 variables to corresponding x2 variables is
foreach {x1 x2} [array get oldvars] {
set $x2 [set $x1]
}
The assignment looks a little off, but what it means is ”assign to the variable whose name is in x2 the value of the variable whose name is in x1.
If you want to do this via a procedure, you need to take into account that the procedure’s code executes in another scope. The uplevel command helps with that, and as a sideeffect the assignment code becomes simpler:
proc o2n {x1 x2} {
upvar 1 $x1 v1 $x2 v2
set v2 $v1
}
foreach {x1 x2} [array get oldvars] {
o2n $x1 $x2
}
Checking existence
If you keep references to variables in the form of variables that store those variables’ names, testing for existence also looks different from the usual. If you have
foreach ele [array names oldvars] {
the variable ele is guaranteed to exist (it is created by foreach as long as the list isn’t empty – but then the body of foreach won’t be executed anyway), but it isn’t the variable you wanted to verify: it only holds the name of the variable you wanted to verify. So you’ll need to write the test like this:
info exists $ele
(you also need to be in the same scope where the variable referenced by ele exists).
This looks very strange since we usually are very careful to verify the name of the variable, not the value. But in this case the value of the variable is the name we want to verify, so.
Inside the procedure it’s easier to write the test. The upvar command creates names in the current scopes that are linked to variables in another scope. If those variables don’t exist, the local names will in effect be names of unset variables.
upvar 1 $x1 v1 $x2 v2
if {[info exists v1]} {
Documentation:
array,
foreach,
if,
info,
proc,
set,
upvar
Related
I want to automate deployments of Vmware VM's in an landscape with lots of portgroups. To be able to select the correct portgroup it would be best to enter 2 variables tenant and environment. These 2 variables are used for CMDB registration and deployment purposes.
For the deployment the variables need to be combined in to 1 new variable to pick the correct portgroup. Due to interpolation syntax it seems to be impossible to use 2 combined variables in the lookup.
How can I combine 2 variables to 1 in Terraform?
I also tried to make a local file with the correct string, but that file needs to exist before the script starts, terraform plan gives a error message that the file doesn't exist.
variable "tenant" {
description = "tenant: T1 or T2"
}
variable "environment" {
description = "environment: PROD or TEST"
}
variable "vm_network" {
description = "network the VM will be provisioned with"
type = "map"
default = {
T1_PROD = "T1-PROD-network"
T2_PROD = "T2-PROD-network"
T1_TEST = "T1-TEST-network"
T2_TEST = "T2-TEST-network"
}
}
data "vsphere_network" "network" {
name = "${lookup(var.vm_network, tenant_environment)}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}
Off the top of my head I can think of three different ways to merge the variables to use as a lookup key:
variable "tenant" {}
variable "environment" {}
variable "vm_network" {
default = {
T1_PROD = "T1-PROD-network"
T2_PROD = "T2-PROD-network"
T1_TEST = "T1-TEST-network"
T2_TEST = "T2-TEST-network"
}
}
locals {
tenant_environment = "${var.tenant}_${var.environment}"
}
output "local_network" {
value = "${lookup(var.vm_network, local.tenant_environment)}"
}
output "format_network" {
value = "${lookup(var.vm_network, format("%s_%s", var.tenant, var.environment))}"
}
output "lookup_network" {
value = "${lookup(var.vm_network, "${var.tenant}_${var.environment}")}"
}
The first option uses locals to create a variable that is interpolated already and can be easily reused in multiple places which can't be done directly with variables in Terraform/HCL. This is generally the best way to do variable combination/interpolation in later versions of Terraform (they were introduced in Terraform 0.10.3).
The second option uses the format function to create a string containing the tenant and environment variables.
The last one is a little funny looking but is valid HCL. I'd probably shy away from using that syntax if possible.
I have 133 variables on income (each variable represents a group). I want the Gini coefficients of all these groups, so I use ineqdeco in Stata. I can't compute all these coefficients by hand so I created a for loop:
gen sgini = .
foreach var of varlist C07-V14 {
forvalue i=1/133 {
ineqdeco `var'
replace sgini[i] = $S_gini
}
}
Also tried changing the order:
foreach var of varlist C07-V14 {
ineqdeco `var'
forvalue i=1/133 {
replace sgini[i] = $S_gini
}
}
And specifying i beforehand:
gen i = 1
foreach var of varlist C07-V14 {
ineqdeco `var'
replace sgini[i] = $S_gini
replace i = i+1
}
}
I don't know if this last method works anyway.
In all cases I get the error: weight not allowed r(101). I don't know what this means, or what to do. Basically, I want to compute the Gini coefficient of all 133 variables, and store these values in a vector of length 133, so a single variable with all the coefficients stored in it.
Edit: I found that the error has to do with the replace command. I replaced this line with:
replace sgini = $S_gini in `i'
But now it does not "loop", so I get the first value in all entries of sgini.
There is no obvious reason for your inner loop. If you have no more variables than observations, then this might work:
gen sgini = .
gen varname = ""
local i = 1
foreach var of varlist C07-V14 {
ineqdeco `var'
replace sgini = $S_gini in `i'
replace varname = "`var'" in `i'
local i = `i' + 1
}
The problems evident in your code (seem to) include:
Confusion between variables and local macros. If you have much experience with other languages, it is hard to break old mental habits. (Mata is more like other languages here.)
Not being aware that a loop over observations is automatic. Or perhaps not seeing that there is just a single loop needed here, the twist being that the loop over variables is easy but your concomitant loop over observations needs to be arranged with your own code.
Putting a subscript on the LHS of a replace. The [] notation is reserved for weights but is illegal there in any case. To find out about weights, search weights or help weight.
Note that with this way of recording results, the Gini coefficients are not aligned with anything else. A token fix for that is to record the associated variable names alongside, as done above.
A more advanced version of this solution would be to use postfile to save to a new dataset.
I am pretty new to tcl language. I am writing a script to automate a process. The code I wrote is below and the contents are read from a file called sample.tcl. The contents of this file changes often.. But I found the values stored in the variable old and new keeps on adding the changes instead of overwriting them. I would like to know what command must be used instead of lappend to do this.
Also if I do a echo $old there is something called tixScrolledListbox added at the beginning of the line. I am not sure what that mean. I would really appreciate if someone could guide me in this. TIA.
set fpp [open sample.tcl]
set b [read $fpp]
set c [split $b "\n"]
set item [llength $c]
set actual_column [expr $item -1]
set actual_item [lreplace $c $actual_column $actual_column]
close $fpp
foreach element $actual_item {
set f [regexp {(.*)\t+(.*)} $element var1 var2 var3]
set var_2 [regsub -all {\s} $var2 {}]
set var_3 [regsub -all {\s} $var3 {}]
lappend old $var_2
lappend new $var_3
}
There are a number of setting commands in Tcl, including lappend and set.
The lappend command sets the value of a variable to be the list contained in the variable (possibly empty) with the assigned value added as a last element (it can also be several values added as a new tail to the old list). This is what you typically use if you want to store a sequence of values.
The set command replaces the value in the variable with the assigned value (or returns the value in the variable, of no second argument is provided). This is what you use if you want to get rid of an old value before you store a new value.
You probably want to write something like this:
set old [list]
set new [list]
foreach element $actual_item {
# ...
lappend old $var_2
lappend new $var_3
}
This will get rid of any previous contents in old and new, and then store a value from each iteration in them.
Your code is a bit hard to figure out, but these lines:
set item [llength $c]
set actual_column [expr $item -1]
set actual_item [lreplace $c $actual_column $actual_column]
seem to mean that you want the variable actual_item to hold all items in c except for the last. If so, you can do that with this invocation instead:
set actual_item [lrange $c 0 end-1]
Note that you should always put the arguments to expr in braces, like
set actual_column [expr {$item - 1}]
This form is safer and more efficient.
You also assign the return value of the regexp call in f but never use that variable.
Would something along the lines of
set fpp [open sample.tcl]
set b [read $fpp]
close $fpp
set old [list]
set new [list]
foreach {o n} [regexp -all -inline -- {[^\n\t]+} $b] {
lappend old [regsub -all {\s} $o {}]
lappend new [regsub -all {\s} $n {}]
}
be helpful? When I use that code on the text
a b 1 2
c d 3 4
(note: there is a tab between the "d" and the "3".)
I get old = ab cd and new = 12 34.
This snippet does not remove the last item in each line. If you still want to do that, it's easy to modify it so it does.
Documentation: close, expr, foreach, lappend, llength, lrange, lreplace, open, read, regexp, set
In real project, TEST_TABLE would contain much of TEST_TABLE_NESTED, each with its own testVariable and bunch of testScript. test function from testScript would be used in C++ code, and TEST_TABLE_NESTED tables would be added automatically from C++ code too.
TEST_TABLE =
{
TEST_TABLE_NESTED =
{
testVariable = 5,
testScript =
{
test = function()
print(testVariable, "hello") --How to access 'testVariable'?
end
}
}
}
EDIT :
This is the actual scenario of using this script:
GameObjectScriptTables =
{
GameObject_1 = --Container of scripts corresponding to some gameObject
{
gameObjectOwner = actual_object_passed_from_c++, --This is an actual object passed from c++
GameObjectScript_1 = --This is a script with update(dt) method which will be called somwhere in c++ code
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
}
}
GameObject_2 =
{
gameObjectOwner = actual_object_passed_from_c++,
GameObjectScript_1 =
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
},
GameObjectScript_2 =
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
}
}
--And so on
}
Idea is that exists some testVariable object (passed from C++), which data is used all over TEST_TABLE_NESTED. For me, above example looks natural for this task, but it prints nil instead of 5. So how to acces a testVariable from testScript without printing a full path like TEST_TABLE.TEST_TABLE_NESTED.testVariable?
You're asking for something like a "parent" pointer, which tells table B about table A, but that doesn't exist. Internally, the only association they have is that one of A's values happens to be B, but any number of tables could contain B as a value. Which is B's parent?
If you want B to know about A, you'll need to tell it. You can add an extra parameter to update which receives the game owner object, or update can be a closure which contains the game owner as a bound variable, so on and so forth.
I made it work by providing a gameObjectOwner instance for each GameObjectScript_N. However I don't know is it expensive solution or not.
There are two script files with the following script
//parent.lua
function scope()
local var = "abc"
require "child"
end
//child.lua
print(var)
This way, child.lua will print a nil value because the scope in parent.lua does not expose its local features to the module. I thought it would, since the require directive is stated within this scope and after the declaration of var. My desire is to practically wholly inject all the lines of the child into the parent. The child script is just exported for better readability. How can I pass the local scope? loadfile() did not work, nor did dofile(). The function environment fenv does not harbor local values. debug.setlocal() does not seem to be able to create new variables (also it would require a receiver in the child). Any method besides recompiling the script?
You can with a bit of effort. If your variables in child are real upvalues you can "link" them to values in your scope function. If they are global variables (which seems to be the case here), you can map them to an environment using setfenv and populate that environment with values from your local variables.
The following will print abc as you'd expect (you can change loadstring to loadfile with the same effect):
function vars(f)
local func = debug.getinfo(f, "f").func
local i = 1
local vars = {}
while true do
local name, value = debug.getlocal(f, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then vars[name] = value end
i = i + 1
end
i = 1
while func do -- check for func as it may be nil for tail calls
local name, value = debug.getupvalue(func, i)
if not name then break end
vars[name] = value
i = i + 1
end
return vars
end
function parent()
local var = "abc"
local child = loadstring("print(var)")
local env = vars(2) -- grab all local/upvalues for the current function
-- use these values to populate new environment; map to _G for everything else
setmetatable(env, {__index = _G})
setfenv(child, env)
child()
end
parent()
This is all for Lua 5.1, but it's also possible in Lua 5.2.