two level splatter TCL - arguments

If I have a procedure or a command in TCL, with variable number of arguments, one can use, if a list's elements are as an input, the "splatter" operator, for example:
set a [list "ko" ]
set m [ list "ok" "bang" ]
lappend a {*}$m
But, what if I want to "twice splatter"? I.e., flatten 2 levels? Using it twice, in sequence, does not work:
set a [list "ko" ]
set m [ list [ list "ok" ] [ list "bang" ] ]
lappend a {*}{*}$m
Will error out on extra character.

You've noticed that {*} (deliberately) doesn't go two steps deep.
Your particular example isn't very indicative of the problem, so I suggest this:
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}$m
Here, we get a set to ko {{a b} {c d}} {{e f} {g h}}. Which isn't what you wanted. But we can instead do this:
lappend a {*}[concat {*}$m]
Which gives this: ko {a b} {c d} {e f} {g h}. That looks right.
But are we really doing the right thing here? Let's poke inside with our super-secret introspector, the representation command:
% tcl::unsupported::representation $m
value is a list with a refcount of 4, object pointer at 0x10085ec50, internal representation 0x103016790:0x0, string representation "{{a b} {c d}}..."
% tcl::unsupported::representation [concat {*}$m]
value is a string with a refcount of 1, object pointer at 0x10085de10, internal representation 0x1030052d0:0x10085f190, string representation "{a b} {c d} {..."
Uh oh! We've lost the list-ness. It's not a catastrophe, but it isn't what we wanted. We instead should really do:
foreach sublist $m {
lappend a {*}$sublist
}
Well, that's more code but preserves list-ness (which would be good if you happened to have precious types on the leaves; core Tcl doesn't have such precious types, but some extensions do).
We can compare the timings:
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
} 10000
2.852789 microseconds per iteration
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
} 10000
4.022959 microseconds per iteration
Oh…
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
}}} 10000
2.4486125 microseconds per iteration
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
}}} 10000
1.6870501 microseconds per iteration
Hah! The type-correct one is better in a procedure(-like context).

The {*} syntax doesn’t really flatten a list per se. Flattening is an execution-level activity, while argument expansion is a parsing-level activity.
% set a a
% lappend a {*}{{a b} {c d}}
In this example, the items in the list {{a b} {c d}} are spliced into the command line as two separate arguments:
% lappend a {a b} {c d}
a {a b} {c d}
If you need to flatten one more level, you should do so with a command “between” the expansions:
% lappend a {*}[concat {*}{{a b} {c d}}]
a a b c d
Documentation:
concat,
lappend,
{*} (syntax),
Summary of Tcl language syntax

Related

Equality test on three or more objects

If I have three or more objects like so:
a = 4
b = 4
c = 4
d = 2
what would be a clean ruby-style way of determining whether they are all equal? Any bespoke methods for running equality tests on three or more elements?
I suppose I could do something like this:
arrays = [a,b,c,d].map{|x| [x]}
arrays.first == arrays.reduce(:&) ? true : false
which appears to work, but feels sort of ham handed, and might be difficult for other developers to read.
[a,b,c,d].any?{|x| x != a}
or
array.any?{|x| x != array.first}
Alternatively, the #all? method may read more intuitively for some:
array.all? {|x| x == array.first }
[a, b, c, d].group_by(&:itself).length == 1
# => false
or
[a, b, c, d].chunk(&:itself).to_a.length == 1
# => false
or
[a, b, c, d].chunk_while(&:==).to_a.length == 1
# => false
or the naive:
[a, b, c, d].uniq.length == 1
I was reminded of one?. Provided that you do not have any falsy element, the above can be written:
[a, b, c, d].uniq.length.one?
I think the answer by #kipar is better by all means, but for the sake of “doing it the way you started” I would post this here:
[a, b, c, d].reduce { |r, e| r == e && r } && true

Split expression into collection of terms

I have a long expression that I would like to split into a collection of terms. For example say I have:
a + b - c + d + 4*e - 3*f
I want to split the expression by addition/subtraction into:
{a, b, -c, d, 4*e, -3*f}
My motivation for this is that I want to deal with the original expression term by term. Is this possible?
Edit: The examples given are VERY simplistic compared to what I'm actually dealing with in Mathematica, it's just that I'm not sure how to write Math around here.
To split the expression, you need to use Level. Level gives you a list of subexpressions and you can specify the level at which you want the subexpressions returned. In this case, you need levelspec 1.
In[1]:= expr = a + b - c + d + 4 e - 3 f;
In[2]:= Level[expr, 1]
Out[2]= {a, b, -c, d, 4 e, -3 f}
An example with a slightly more complicated expression:
In[3]:= expr2 = a^2 + 5 bc/ef - Sqrt[g - h] - Cos[i]/Sin[j + k];
In[4]:= Level[expr2, 1]
Out[4]= {a^2, (5 bc)/ef, -Sqrt[g - h], -Cos[i] Csc[j + k]}
Since no one else has mentioned it, equivalent to Yoda's Level[expr, 1] construction is to use Apply to replace the head of an expression with List:
In[1]:= expr = a + b - c + d + 4 e - 3 f;
In[2]:= List ## expr
Level[expr, 1] == %
Out[2]= {a, b, -c, d, 4 e, -3 f}
Out[3]= True
In[4]:= expr2 = a^2 + 5 bc/ef - Sqrt[g - h] - Cos[i]/Sin[j + k];
In[5]:= List ## expr2
Level[expr2, 1] == %
Out[5]= {a^2, (5 bc)/ef, -Sqrt[g - h], -Cos[i] Csc[j + k]}
Out[6]= True
The two methods do basically the same thing and have identical timings (using my version of a average timing function)
In[1]:= SetOptions[TimeAv, Method -> {"MinNum", 80000}, "BlockSize" -> 20000];
In[7]:= List ## expr // TimeAv
Total wall time is 0.244517, total cpu time is 0.13
and total time spent evaluating the expression is 0.13
The expression was evaluated 80000 times, in blocks of 20000 runs. This yields
a mean timing of 1.625*10^-6 with a blocked standard deviation of 2.16506*10^-7.
Out[7]= {1.625*10^-6, {a, b, -c, d, 4 e, -3 f}}
In[8]:= Level[expr, 1] // TimeAv
Total wall time is 0.336927, total cpu time is 0.16
and total time spent evaluating the expression is 0.16
The expression was evaluated 80000 times, in blocks of 20000 runs. This yields
a mean timing of 2.*10^-6 with a blocked standard deviation of 3.53553*10^-7.
Out[8]= {2.*10^-6, {a, b, -c, d, 4 e, -3 f}}
You might also be able to use MonomialList, if you expression is a polynomial:
In[56]:= MonomialList[a + b - c + d + 4*e - 3*f]
Out[56]= {a, b, -c, d, 4 e, -3 f}
(Doesn't work on non-polynomials, such as Yoda's expr2.)
You could also use Replace:
In[65]:= Replace[a + b - c + d + 4*e - 3*f, HoldPattern[Plus[a___]] :> {a}]
Out[65]= {a, b, -c, d, 4 e, -3 f}
You need to use HoldPattern (or some equivalent trick) to prevent Plus[a__] from evaluating to a__, which has the result of just wrapping the first argument in a list instead of creating a list of the arguments to Plus.

(a && b) versus (a and b)

Given :
a=true
b=false
why can I do :
puts [a && b, a || b] #[false, true]
but not
puts [a and b, a or b]
syntax error, unexpected keyword_and, expecting ']'
puts [a and b, a or b]
Apparently, the operator precedence for the comma is higher than "and" but lower than &&.
Putting parenthesis around the elements works:
[(a and b), (a or b)]
you need to simply group the terms to avoid precedence issues:
puts [(a and b),(a or b)]

How to enum the patterns

How to generate all patterns in the following rule:
# as a separator, { and } means choose a string between { and }.
For example:
Input: a string
{a # b} c {d # e {f # g}}
Output should be:
a c d
b c d
a c e f
a c e g
First, parse the input string into a tree using any standard parsing algorithm. The tree-form expression for your example above would be something like (C = concatenate, S = select)
C(S(a,b),C(c,S(d,C(e,S(f,g)))))
Now then implement a procedure that recursively evaluates this tree (or expression, as you might call it) and returns a set of strings as the result of evaluation any subexpression. Then the evaluation goes like this
S(f,g) == "f", "g"
C(e,S(f,g)) == "ef", "eg"
S(d,C(e,S(f,g))) = "d", "ef", "eg"
C(c,S(d,C(e,S(f,g)))) = "cd", "cef", "ceg"
S(a,b) = "a", "b"
C(S(a,b),C(c,S(d,C(e,S(f,g))))) = "acd", "bcd", "acef", "bcef", "aceg", "bceg"
(by the way, you are missing bcef and bceg from your example)
The evaluation rules are:
S(X,Y) : evaluate X and Y and take the union of the sets
C(X,Y) : evaluate X and Y and form all concatenations from taking one string from set X and one string from set Y

How should I write a function to be used in Apply in Mathematica?

I am wondering how I can write a function to be used in the Apply function in Mathematica? For example, I want to trivially re-implement the Or function, I found the following
Apply[(#1 || #2)&,{a,b,c}]
is not okay since it only Or'ed the first two elements in the list. Many thanks!
This will work, no matter how many vars, and is a general pattern:
Or[##]&,
for example
In[5]:= Or[##] & ## {a, b, c}
Out[5]= a || b || c
However, in the case of Or, this is not good enough, since Or is HoldAll and short-circuiting - that is, it stops upon first True statement, and keeps the rest unevaluated. Example:
In[6]:= Or[True, Print["*"]]
Out[6]= True
In[7]:= Or[##] & ## Hold[True, Print["*"]]
During evaluation of In[7]:= *
Out[7]= True
This will be ok though:
Function[Null,Or[##],HoldAll],
for example,
In[8]:= Function[Null, Or[##], HoldAll] ## Hold[True, Print["*"]]
Out[8]= True
and can be used in such cases (when you don't want your arguments to evaluate). Note that this uses an undocumented form of Function. The mention of this form can be found in the book of R.Maeder, "Programming in Mathematica".
HTH
Or ## {a, b, c}
Equivalent
Apply[Or, {a, b, c}]
Equivalent
{a, b, c} /. {x_, y__} -> Or[x, y]
Apply works like this:
{2 #1, 3 #2, 4 #3} & ## {a, b, c}
{2 a, 3 b, 4 c}
Plus[2 #1, 3 #2, 4 #3] & ## {a, b, c}
2 a + 3 b + 4 c
Are you sure you are expecting the right thing from Apply? If you look in the documentation, http://reference.wolfram.com/mathematica/ref/Apply.html, you will see that Apply[f,expr] simply replaces the head of f by expr. It does not, in general, give f[expr].
If you wish to operate with function f onto expr, try f#expr or f[expr].
Perhaps you understand the above and your question really is, "how do I define some f that, when I do Apply[f,{a,b,c}], does the same job as Or[a,b,c]. Is that it?

Resources