Two consecutive identical calls to echo have different output in Vim function - recursion

Original post on Vi and Vim Beta, which has had one interesting answer, but not much attention so far. I am sorry for the crossposting and I will ask for the original to be closed/deleted.
Given the following function in the .vimrc file,
fu! MyFun(count)
echo a:count
echo a:count
if a:count > 0
normal ,
call MyFun(a:count - 1)
endif
endf
calling :call MyFun(3) generates the following output.
3
3
2
2
1
1
0
0
However, if I define the mapping nn , :<C-U>execute "call MyFun(" . v:count . ")"<CR>, then the call to :call MyFun(3) generates
3
0
2
0
1
0
0
0
I do understand that the mapping of , makes the MyFun function call itself twice (if a:count > 0), however I cannot understand how this can cause a different result of the two successive calls to echo a:count.

The problem is all about screen redraw (see :h echo-redraw) in Vim.
Changing echo to echom still produces the same (broken) screen output (3 0 2 0 1 0 0 0), but :mess reveals what is hidden: 3 3 0 0 2 2 0 0 1 1 0 0 0 0.

Related

The not operator (!) isn't working with array broadcasting

I am wondering why the not operator isn't working with array broadcasting/element-wise operations. For example, if I enter
x = Array{Any}([1,2,3,4,missing,6])
!ismissing.(x)
I get an error ERROR: MethodError: no method matching !(::BitArray{1})
but if I try ismissing.(x) it works fine,
ismissing.(x)
#out > 6-element BitArray{1}: 0 0 0 0 1 0
and typing without the broadcasting works as a whole as well (one output for the entire array)
!ismissing(x)
#out > True
So I am wondering if there is a possibility to get a similar result as using the "!" operator.
You need to also broadcast ! to each element:
julia> x = Array{Any}([1,2,3,4,missing,6]);
julia> .!(ismissing.(x)) # the . comes before operators (!, +, -, etc)
6-element BitVector:
1
1
1
1
0
1
For this specific case you can instead negate the function before broadcasting:
julia> (!ismissing).(x)
6-element BitVector:
1
1
1
1
0
1

TCL recursively call procedure

I'm a beginner at TCL and while trying to build the GCD algorithm I ran into some problems I'd like some help with:
how can I call a proc inside a proc recursively like so
proc Stein_GCD { { u 0 } { v 0 } } {
if { $v == 0 } {
puts "$u\t\t$v\t\t$v"
}
if { [expr { $v % 2 } && { $u % 2 } ] == 0 } {
return [expr 2 * ${Stein_GCD 1 0} ]
}
}
set a [Stein_GCD 2 2 ]
puts $a
as you can see, I made the proc to evaluate GCD(the code does not make any sense because I'm trying to solve an example issue), and I'm trying to recursively call the proc again to continue evaluating(notice that I made an if statement that can understand the Stein_GCD 1 0 call, yet the tcl 8.6.6 online EDA emulator says:
can't read "Stein_GCD 1 0": no such variable
while executing
"expr 2 * ${Stein_GCD 1 0} "
(procedure "Stein_GCD" line 5)
invoked from within
"Stein_GCD 2 2 "
invoked from within
"set a [Stein_GCD 2 2 ]"
(file "main.tcl" line 7)
Can you tell me how to efficiently recursively call a proc, and where was my mistake?
will gladly provide more info in the case I did a bad job at explaining.
The error can't read "Stein_GCD 1 0": indicates that you are treating the data as a single string instead of separate arguments. The problem line:
return [expr 2 * ${Stein_GCD 1 0} ]
is not written correctly. ${Stean_GCD 1 0} is not a variable.
You should have:
return [expr 2 * [Stein_GCD 1 0] ]
You want the result from Stein_GCD 1 0, so the brackets should be used.

Cannot index 2D array with (attempt to index field '?' (a nil value) )

I have 2 different 2d Arrays set up in lua. The first loop
bubbleMat = {} --Set Up Table called bubbleMat
for i = 1, 10 do
bubbleMat[i] = {} --1D table with 10 components
for j = 1, 13 do
bubbleMat[i][j] = bubbleClass.new( (i*62) - 62, (j*62) - 62 ) --2D Table with 10x13 Matrix each cell given a coordinate as it is iterated through the loop
end
end
With this array i can print value of any position in the array to the console with
print(bubbleMat[x][y])
for whatever numbers of x and y
The second array for some reason does not work. The second array is as follows
bubbleMat = {} --Set Up Table called bubbleMat
for j = 1, 13 do
for i = 1, 10 do
bubbleMat[i] = {}
--bubbleMat[i][j] = {}
if j%2 == 0 then
bubbleMat[i][j] = bubbleClass.new( (i*62) - 31, (j*62) - 62 )
else
bubbleMat[i][j] = bubbleClass.new( (i*62) - 62, (j*62) - 62 )
end
end
end
print(bubbleMat)
I am unsure why I cannot index the second array
this is the following error I get in the console
attempt to index field '?' (a nil value)
Thanks in advance for any help.
Basically i want to display a grid of bubbles stored in a 2d array in the following pattern
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
as opposed to having the bubbles in the next line positioned directly underneath
Loop for j is outside and loop for i is inside. This is not necessarily false, but unusual.
However, bubbleMat[i] is initialized to {} in the innermost loop, which is clearly wrong.
Either move that initialization into the outermost loop, or use this syntax :
bubbleMat[i] = bubbleMat[i] or {}

What algorithm I need to find n-grams?

What algorithm is used for finding ngrams?
Supposing my input data is an array of words and the size of the ngrams I want to find, what algorithm I should use?
I'm asking for code, with preference for R. The data is stored in database, so can be a plgpsql function too. Java is a language I know better, so I can "translate" it to another language.
I'm not lazy, I'm only asking for code because I don't want to reinvent the wheel trying to do an algorithm that is already done.
Edit: it's important know how many times each n-gram appears.
Edit 2: there is a R package for N-GRAMS?
If you want to use R to identify ngrams, you can use the tm package and the RWeka package. It will tell you how many times the ngram occurs in your documents, like so:
library("RWeka")
library("tm")
data("crude")
BigramTokenizer <- function(x) NGramTokenizer(x, Weka_control(min = 2, max = 2))
tdm <- TermDocumentMatrix(crude, control = list(tokenize = BigramTokenizer))
inspect(tdm[340:345,1:10])
A term-document matrix (6 terms, 10 documents)
Non-/sparse entries: 4/56
Sparsity : 93%
Maximal term length: 13
Weighting : term frequency (tf)
Docs
Terms 127 144 191 194 211 236 237 242 246 248
and said 0 0 0 0 0 0 0 0 0 0
and security 0 0 0 0 0 0 0 0 1 0
and set 0 1 0 0 0 0 0 0 0 0
and six-month 0 0 0 0 0 0 0 1 0 0
and some 0 0 0 0 0 0 0 0 0 0
and stabilise 0 0 0 0 0 0 0 0 0 1
hat-tip: http://tm.r-forge.r-project.org/faq.html
For anyone still interested in this topic, there is a package on the cran already.
ngram: An n-gram Babbler
This package offers utilities for creating, displaying, and "babbling" n-grams. The babbler is a simple Markov process.
http://cran.r-project.org/web/packages/ngram/index.html
Usually the n-grams are calculated to find its frequency distribution. So Yes, it does matter how many times the n-grams appear.
Also you want character level n-gram or word level n-gram. I have written a code for finding the character level n-gram from a csv file in r. I used package 'tau' for that. You can find it here.
Also here is the code I wrote:
library(tau)
temp<-read.csv("/home/aravi/Documents/sample/csv/ex.csv",header=FALSE,stringsAsFactors=F)
r<-textcnt(temp, method="ngram",n=4L,split = "[[:space:][:punct:]]+", decreasing=TRUE)
a<-data.frame(counts = unclass(r), size = nchar(names(r)))
b<-split(a,a$size)
b
Cheers!
EDIT: Sorry, this is PHP. I wasn't quite sure what you wanted. I don't know it in java but perhaps the following could be converted easily enough.
Well it depends on the size of the ngrams you want.
I've had quite a lot of success with single letters (especially accurate for language detection), which is easy to get with:
$letters=str_split(preg_replace('/[^a-z]/', '', strtolower($text)));
$letters=array_count_values($letters);
Then there is the following function for calculating ngrams from a word:
function getNgrams($word, $n = 3) {
$ngrams = array();
$len = strlen($word);
for($i = 0; $i < $len; $i++) {
if($i > ($n - 2)) {
$ng = '';
for($j = $n-1; $j >= 0; $j--) {
$ng .= $word[$i-$j];
}
$ngrams[] = $ng;
}
}
return $ngrams;
}
The source of the above is here, which I recommend you read, and they have lots of functions to do exactly what you want.
You can use ngram package. One example of its usage is http://amunategui.github.io/speak-like-a-doctor/
Have a look at https://cran.r-project.org/web/packages/ngram/vignettes/ngram-guide.pdf
Here is a quick example. It's quite fast look at the benchmark of the vignette.
require(ngram)
"hi i am ig" %>% ngram(n = 2) %>% get.ngrams()
Simple heres the java answer:
int ngrams = 9;// let's say 9-grams since it's the length of "bonasuera"...
String string = "bonasuera";
for (int j=1; j <= ngrams;j++) {
for (int k=0; k < string.length()-j+1;k++ )
System.out.print(string.substring(k,k+j) + " ");
System.out.println();
}
output :
b o n a s u e r a
bo on na as su ue er ra
bon ona nas asu sue uer era
bona onas nasu asue suer uera
bonas onasu nasue asuer suera
bonasu onasue nasuer asuera
bonasue onasuer nasuera
bonasuer onasuera
bonasuera

Optimising R function that adds a new column to a data.frame

I have a function that at the moment programmed in a functional model and either want to speed it up and maybe solve the problem more in the spirit of R.
I have a data.frame and want to add a column based on information that's where every entry depends on two rows.
At the moment it looks like the following:
faultFinging <- function(heartData){
if(heartData$Pulse[[1]] == 0){
Group <- 0
}
else{
Group <- 1
}
for(i in seq(2, length(heartData$Pulse), 1)){
if(heartData$Pulse[[i-1]] != 0
&& heartData$Pulse[[i]] != 0
&& abs(heartData$Pulse[[i-1]] - heartData$Pulse[[i]])<20){
Group[[i]] <- 1
}
else{
if(heartData$Pulse[[i-1]] == 0 && heartData$Pulse[[i]] != 0){
Group[[i]] <- 1
}
else{
Group[[i]] <- 0
}
}
}
Pulse<-heartData$Pulse
Time<-heartData$Time
return(data.frame(Time,Pulse,Group))
}
I can't test this without sample data, but this is the general idea. You can avoid doing the for() loop entirely by using & and | which are vectorized versions of && and ||. Also, there's no need for an if-else statement if there's only one value (true or false).
faultFinging <- function(heartData){
Group <- as.numeric(c(heartData$Pulse[1] != 0,
(heartData$Pulse[-nrow(heartData)] != 0
& heartData$Pulse[-1] != 0
& abs(heartData$Pulse[-nrow(heartData)] - heartData$Pulse[-1])<20) |
(heartData$Pulse[-nrow(heartData)] == 0 & heartData$Pulse[-1] != 0)))
return(cbind(heartData, Group))
}
Putting as.numeric() around the index will set TRUE to 1 and FALSE to 0.
This can be done in a more vector way by separating your program into two parts: firstly a function which takes two time samples and determines if they meet your pulse specification:
isPulse <- function(previous, current)
{
(previous != 0 & current !=0 & (abs(previous-current) < 20)) |
(previous == 0 & current !=0)
}
Note the use of vector | instead of boolean ||.
And then invoke it, supplying the two vector streams 'previous' and 'current' offset by a suitable delay, in your case, 1:
delay <- 1
samples = length(heartData$pulse)
isPulse(heartData$pulse[-(samples-(1:delay))], heartData$pulse[-(1:delay)])
Let's try this on some made-up data:
sampleData = c(1,0,1,1,4,25,2,0,25,0)
heartData = data.frame(pulse=sampleData)
result = isPulse(heartData$pulse[-(samples-(1:delay))], heartData$pulse[-(1:delay)])
Note that the code heartData$pulse[-(samples-(1:delay))] trims delay samples from the end, for the previous stream, and heartData$pulse[-(1:delay)] trims delay samples from the start, for the current stream.
Doing it manually, the results should be (using F for false and T for true)
F,T,T,T,F,F,F,T,F
and by running it, we find that they are!:
> print(result)
FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE FALSE
success!
Since you want to bind these back as a column into your original dataset, you should note that the new array is delay elements shorter than your original data, so you need to pad it at the start with delay FALSE elements. You may also want to convert it into 0,1 as per your data:
resultPadded <- c(rep(FALSE,delay), result)
heartData$result = ifelse(resultPadded, 1, 0)
which gives
> heartData
pulse result
1 1 0
2 0 0
3 1 1
4 1 1
5 4 1
6 25 0
7 2 0
8 0 0
9 25 1
10 0 0

Resources