variables/arrays from tcl procedure - variables

How could i pass some variables/ arrays outside of procedure?
Lets say I've my procedure 'myproc' with inputparameters {a b c d e}, e.g.
myproc {a b c d e} {
... do something
(calculate arrays, lists and new variables)
}
Inside this procedure I want to calculate an array phiN(1),phiN(2),...phiN(18) out of the variables a-e which itself is a list, e.g.
set phiN(1) [list 1 2 3 4 5 6 7 8 9];
(lets say the values 1-9 had been calculated out of the input variables a-e). And I want to calculate some other parameter alpha and beta
set alpha [expr a+b];
set beta [expr c+d];
Anyway no I want to pass these new calculated variables outside of my procedure. Compare to matlab I simply would write sg like to get these variables outside of the 'function'.
[phiN,alpha,beta] = myproc{a b c d e}
Has anybody an idea how I can deal in tcl?? Thanks!

There are several options:
Return a list and use lassign outside
Example:
proc myproc {a b c d e} {
set alpha [expr {$a+$b}]
set beta [expr {$c+$d}]
return [list $alpha $beta]
}
lassign [myproc 1 2 3 4 5] alpha beta
This is fine if you return values, but not arrays.
Use upvar and provide the name of the array/variable as argument
Example:
proc myproc {phiNVar a b c d e} {
upvar 1 $phiNVar phiN
# Now use phiN as local variable
set phiN(1) [list 1 2 3 4 5 6 7 8 9]
}
# Usage
myproc foo 1 2 3 4 5
foreach i $foo(1) {
puts $i
}
Use a combination of both
Example:
proc myproc {phiNVar a b c d e} {
uplevel 1 $phiNVar phiN
set alpha [expr {$a+$b}]
set beta [expr {$c+$d}]
set phiN(1) [list 1 2 3 4 5 6 7 8 9]
return [list $alpha $beta]
}
lassign [myproc bar 1 2 3 4 5] alpha beta
foreach i $bar(1) {
puts $i
}
Edit: As Donal suggested, is is also possible to return a dict:
A dict is a Tcl list where the odd elements are the keys and the even elements are the values. You can convert an array to a dict with array get and convert a dict back to an array with array set. You can also use the dict itself.
Example
proc myproc {a b c d e} {
set alpha [expr {$a+$b}]
set beta [expr {$c+$d}]
set phiN(1) [list 1 2 3 4 5 6 7 8 9]
return [list [array get phiN] $alpha $beta]
}
lassign [myproc 1 2 3 4 5] phiNDict alpha beta
array set bar $phiNDict
foreach i $bar(1) {
puts $i
}
# Use the [dict] command to manipulate the dict directly
puts [dict get $phiNDict 1]
For more ideas (this is about arrays, but could apply to values as well) see this wiki entry.

Related

Build a decision Column by ANDing multiple columns in pandas

I have a pandas data frame which is shown below:
>>> x = [[1,2,3,4,5],[1,2,4,4,3],[2,4,5,6,7]]
>>> columns = ['a','b','c','d','e']
>>> df = pd.DataFrame(data = x, columns = columns)
>>> df
a b c d e
0 1 2 3 4 5
1 1 2 4 4 3
2 2 4 5 6 7
I have an array of objects (conditions) as shown below:
[
{
'header' : 'a',
'condition' : '==',
'values' : [1]
},
{
'header' : 'b',
'condition' : '==',
'values' : [2]
},
...
]
and an assignHeader which is:
assignHeader = decision
now I want to do an operation which builds up all the conditions from the conditions array by looping through it, for example something like this:
pConditions = []
for eachCondition in conditions:
header = eachCondition['header']
values = eachCondition['values']
if eachCondition['condition'] == "==":
pConditions.append(df[header].isin(values))
else:
pConditions.append(~df[header].isin(values))
df[assignHeader ] = and(pConditions)
I was thinking of using all operator in pandas but am unable to crack the right syntax to do so. The list I shared can go big and dynamic and so I want to use this nested approach and check for the equality. Does anyone know a way to do so?
Final Output:
conditons = [df['a']==1,df['b']==2]
>>> df['decision'] = (df['a']==1) & (df['b']==2)
>>> df
a b c d e decision
0 1 2 3 4 5 True
1 1 2 4 4 3 True
2 2 4 5 6 7 False
Here conditions array will be variable. And I want to have a function which takes df, 'newheadernameandconditions` as input and returns the output as shown below:
>>> df
a b c d e decision
0 1 2 3 4 5 True
1 1 2 4 4 3 True
2 2 4 5 6 7 False
where newheadername = 'decision'
I was able to solve the problem using the code shown below. I am not sure if this is kind of fast way of getting things done, but would love to know your inputs in case you have any specific thing to point out.
def andMerging(conditions, mergeHeader, df):
if len(conditions) != 0:
df[mergeHeader] = pd.concat(conditions, axis = 1).all(axis = 1)
return df
where conditions are an array of pd.Series with boolean values.
And conditions are formatted as shown below:
def prepareForConditionMerging(conditionsArray, df):
conditions = []
for prop in conditionsArray:
condition = prop['condition']
values = prop['values']
header = prop['header']
if type(values) == str:
values = [values]
if condition=="==":
conditions.append(df[header].isin(values))
else:
conditions.append(~df[header].isin(values))
# Here we can add more conditions such as greater than less than etc.
return conditions

Multiply String in Dataframe?

My desired output is the following:
count tally
1 2 //
2 3 ///
3 5 /////
4 3 ///
5 2 //
My code:
my_list = [1,1,2,2,2,3,3,3,3,3,4,4,4,5,5]
my_series = pd.Series(my_list)
values_counted = pd.Series(my_series.value_counts(),name='count')
# other calculated columns left out for SO simplicity
df = pd.concat([values_counted], axis=1).sort_index()
df['tally'] = values_counted * '/'
With the code above I get the following error:
masked_arith_op
result[mask] = op(xrav[mask], y)
numpy.core._exceptions.UFuncTypeError: ufunc 'multiply' did not contain a loop with signature matching types (dtype('<U21'), dtype('<U21')) -> dtype('<U21')
In searching for solutions I found one on SO that said to try:
values_counted * float('/')
But that did not work.
In 'normal' Python outside of Dataframes the following code works:
10 * '/'
and returns
///////////
How can I achieve the same functionality in a Dataframe?
Use lambda function for repeat values, your solution is simplify:
my_list = [1,1,2,2,2,3,3,3,3,3,4,4,4,5,5]
df1 = pd.Series(my_list).value_counts().to_frame('count').sort_index()
df1['tally'] = df1['count'].apply(lambda x: x * '/')
print (df1)
count tally
1 2 //
2 3 ///
3 5 /////
4 3 ///
5 2 //
You can group the series by itself and then aggregate:
new_df = my_series.groupby(my_series).agg(**{"count": "size",
"tally": lambda s: "/" * s.size})
to get
>>> new_df
count tally
1 2 //
2 3 ///
3 5 /////
4 3 ///
5 2 //

Divide list with the single number in tcl NS-2

i want to divide the whole list with one number.Lets say i take a variable $Content and i want to divide the following list with the 300 nodes.
so i take the command $Content/300
$Content= {1 2 3 4 5}{ 2 3 4 5 6} { 4 5 6 7 8 9}{3 4 6 8 9 0}
As a result output comes out {1 2 3 4 5}{ 2 3 4 5 6} { 4 5 6 7 8 9}{3 4 6 8 9 0}/300 with the parenthesis missing and invalid arguments.
Please tell me how we divide all list with the single number(300 nodes) because in curly brackets each number comes as an output of some arguments
Note that Tcl is a very whitespace-sensitive language, so you need a space between the close and open braces in your $Content declaration.
You can iterate over $Content, and for each sublist, iterate over the elements and divide by 300, collecting the results:
set Content {{1 2 3 4 5} { 2 3 4 5 6} { 4 5 6 7 8 9} {3 4 6 8 9 0}}
# note the spaces ......^............^..............^
set divisor 300
set newContent [list]
foreach sublist $Content {
set newSublist [list]
foreach elem $sublist {
lappend newSublist [expr {$elem * 1.0 / $divisor}]
}
lappend newContent $newSublist
}
puts $newContent
Output is
{0.0033333333333333335 0.006666666666666667 0.01 0.013333333333333334 0.016666666666666666} {0.006666666666666667 0.01 0.013333333333333334 0.016666666666666666 0.02} {0.013333333333333334 0.016666666666666666 0.02 0.023333333333333334 0.02666666666666667 0.03} {0.01 0.013333333333333334 0.02 0.02666666666666667 0.03 0.0}
If your Tcl version is 8.6 you can use the lmap command to shorten up the code:
set newContent [lmap sublist $Content {
lmap elem $sublist {expr {$elem * 1.0 / $divisor}}
}]
Note that I multiply by 1.0 in order to use float division and not integer division.

Fastest way to eliminate consecutive duplicates from array in objective-C

Prepping for interview. Trying to work out a solution for the question "Fastest way to eliminate consecutive duplicates from array" using objective-C. I.e input =[1,2,2,1,2,3,3,4] output =[1,2,1,2,3,4]
For in-array approach: Loop through element in array, if element == previous element, remove it and readjust all other elements to move step down.
For approach where we can use another array. If element == previous element, don't add it to new "Unique array", else add it to Unique array.
Are there any better solutions? Code is below. Any optimizations possible?
Using another array
//Pseudocode for sucessive dup elimination when using another array
//
//duplicateLessArray = empty array
//previous element = not set
//
//for (loop through each element in origArray)
// if(previous element == not set or element != previous element)
// set previousElement = element
// add element to duplicateLessArray
//
NSMutableArray *duplicateLessArray ;
duplicateLessArray = [[NSMutableArray alloc] init] ;
for (NSNumber *nextNumber in origArray)
{
if ([nextNumber intValue] != [[duplicateLessArray lastObject] intValue])
{
[duplicateLessArray addObject:nextNumber] ;
}
}
NSLog(#"Duplicate less array = %#",duplicateLessArray) ;
Using same array
//Pseudocode for in array sucessive dup elimination
//
//previous element = not set
//
//for (loop through each element in origArray)
// if(previous element == not set or element != previous element)
// set previousElement = element
// else
// delete it from origArray
// move back all elements by 1
NSInteger numElementsInDupLessArray = 0 ;
NSNumber *prevElement ;
for (NSNumber *nextNumber in [origArray copy])
{
if (numElementsInDupLessArray == 0 || [nextNumber intValue] != [prevElement intValue])
{
prevElement=nextNumber ;
numElementsInDupLessArray++;
}
else
{
[origArray removeObjectAtIndex:numElementsInDupLessArray] ;
}
}
NSLog(#"Duplicate less array = %#",origArray) ;
There is optimization for in-array approach:
Instead of removing elements one-by-one (this may cause O(n^2) complexity) just shift single elements.
Pseudocode:
numOfRemoved = 0
GoodValue = A[0]
for i = 1 to arrayEnd //note start from 2nd element
if A[i] = GoodValue then
numOfRemoved++
else
GoodValue = A[i]
A[i-numOfRemoved] = A[i]
Resize array once to (Length - numOfRemoved)
Example (' denotes current element, nr is numOfRemoved)
[5 5 1 7 7 7 4] nr = 0 ; 5 stays at index 0
[5 '5 1 7 7 7 4] nr = 0->1
[5 5 '1 7 7 7 4] nr = 1 ; 1 goes to index 2-1 = 1
[5 1 1 '7 7 7 4] nr = 1 ; 7 goes to index 2
[5 1 7 7 '7 7 4] nr = 1->2
[5 1 7 7 7 '7 4] nr = 2->3
[5 1 7 4 7 7 '4] nr = 3 ; 4 goes to index 6-3 = 3
[5 1 7 4] resize

copy/part with pair in REBOL 3

help copy has the following to say about copy:
USAGE:
COPY value /part length /deep /types kinds
DESCRIPTION:
Copies a series, object, or other value.
COPY is an action value.
ARGUMENTS:
value -- At position (series! port! map! object! bitset! any-function!)
REFINEMENTS:
/part -- Limits to a given length or position
length (number! series! pair!)
/deep -- Also copies series values within the block
/types -- What datatypes to copy
kinds (typeset! datatype!)
The /part refinement can take a number!, series! or pair!. I have not been able to get pair! to work. (I haven't tried series! yet.) Is this not implemented? If it is, how does it work?
The /part pair! refinement works with images. The pair relates to the x/y coordinates as in
>> img: load %image.png
== make image! [519x391 #{
1D2F9F1D2F9F1C2E9E1C2E9E1B2D9D1B2D9D1B2D9D1B2D9D1D2F9F1C2E9E
1A2C9C192B9B192B9B1A2C9C1B2D9D1C2E9E1D2EA01...
>> copy/part img 2x2
== make image! [2x2 #{
1D2F9F1D2F9F1D2F9F1D2F9F
}]
REBOL/View Image Datatype
And here an example how /part series! is working
>> s: [a b c d e f g]
== [a b c d e f g]
>> ser: skip s 3
== [d e f g]
>> copy/part s ser
== [a b c]