How do the parameters to ;. (Cut) work? - j

What does <;._1 mean?
data=:',MARY,PATRICIA,LINDA,BARBARA'
<;._1 data

;. is cut: u ;. x y
_1 (x) means "split by the first character"; which is , in this case
< (u) is the verb to apply to each "split". < is box
data (y) is where you apply the cut.
In other words: "Box each split that is made by cutting data at ,s".

Related

How can I fix 'noun result was required' error in J?

I'm trying to do the 4th Advent of Code problem using J, and I've ran into lots of problems, but now I have a code that looks like this:
fn =. < 'D:/PyCharm/AOC/output4.txt'
data =. freads fn
concatIntegers =. ,&'x'#,&.":
separado =. ;: data
lista =. > ((i.(#separado)%2)*2) {separado
n_lista =. #lista
n_2 =. n_lista % 4
lista_2 =. concatIntegers each/|:lista
matriz =. 250 4 $ > lista_2
loop =: monad : 0
res =. 0
i=.0
condicion=.0
for_i. i.250 do.
fila =. i { matriz
elfo11 =. 0 {fila
elfo12 =. 1 {fila
elfo21 =. 2 {fila
elfo22 =. 3 {fila
condicion =. ((elfo11 <: elfo21) *. (elfo12 >: elfo22)) +. ((elfo21 <: elfo11) *. (elfo22 >: elfo12))
if. condicion do.
res =. >: res
end.
end.
res
)
loop matriz
What this should do is: Loads a txt file, parses it, creates a matrix, and then using the verb loop it would add 1 to a counter every time the condition is applied.
The thing is, I can't make that loop work, every time I try running it, it gives me the same error:
|noun result was required: loop
| condicion
|[-30] d:\pycharm\aoc\day4.ijs
I am losing my mind
The code works until it reaches the loop verb I created, but I've been looking through documentation for ages and I can't spot my error
The code until that works as intended
Problem #1: variable i used in:
fila =. i { matriz
is not defined and is considered as unknown verb not noun.
Problem #2: loop iterates on martiz which is of lenght 250 elements (each element is list of 4 integers). But it does 1000 iterations, so there is out of array bound here.
Try to replace the line:
for. i.1000 do.
by the line
for_i. i.250 do.
Problem #3: there is no priorities for operators, so condition should be computed as (I guess here):
condicion =. ((elfo11 <: elfo21) *. (elfo12 >: elfo22)) +. ((elfo21 <: elfo11) *. (elfo22 >: elfo12))
Problem #4: res increment is not saved, try to replace the line:
>: res
by the line
res=. >: res
Problem #5: loop verb cannot see martiz noun since that is local, try to replace the line:
matriz =. 250 4 $ > lista_2
by the line
matriz =: 250 4 $ > lista_2

Sorting words in a string by their length in J

I have the following string:
s=:'when can we dance'
I can find the length of each word with this:
# each ;:s
I can sort the lengths in ascending/descending order:(/:~) # each ;:s which gives me boxed output.
But how do I get the words printed?
You're already using /:~ which is the Reflex of dyadic Sort Up; /:~ y is equivalent to y /: y. This is a convenient shortcut, but it this case what you're skipping past is the solution you're looking for. /: (without Reflex) permutes its x according to the permutation that would result in a sorted y. That "permutation that would result in a sorted y" is incidentally what monadic /:
(Grade Up) is for.
]w=:;:'when can we dance'
+----+---+--+-----+
|when|can|we|dance|
+----+---+--+-----+
/: w
1 3 2 0
(/: w) { w
+---+-----+--+----+
|can|dance|we|when|
+---+-----+--+----+
w /: w
+---+-----+--+----+
|can|dance|we|when|
+---+-----+--+----+
So to sort w by something else, like the lengths of its items, just provide that something else as Sort Up's y:
w /: # each w
+--+---+----+-----+
|we|can|when|dance|
+--+---+----+-----+
(/: # each) w NB. a hook
+--+---+----+-----+
|we|can|when|dance|
+--+---+----+-----+
;: gives you the J words in a string, which might not be what you want:
;: 'when can''t we dance'
|open quote
| ;:'when can''t we dance'
One of the ;. Cut family or stdlib's splitstring or regexes might help.
13 : ';: ''when can we dance''' NB. 13 : can be a mnemonic
(<;._1 ' when can we dance')"_
<;._1 ' ','when can''t we dance'
+----+-----+--+-----+
|when|can't|we|dance|
+----+-----+--+-----+
' ' splitstring 'when can''t we dance'
+----+-----+--+-----+
|when|can't|we|dance|
+----+-----+--+-----+
s=:'when can''t we dance' NB. excess space
<;._1 ' ',s NB. empty boxes in result
+----+-----+++--+-----+
|when|can't|||we|dance|
+----+-----+++--+-----+
require 'regex'
'[\w'']+' rxall s
+----+-----+--+-----+
|when|can't|we|dance|
+----+-----+--+-----+
To get these word-lists back into a string,
w
+----+---+--+-----+
|when|can|we|dance|
+----+---+--+-----+
;: inv w
when can we dance
' ' joinstring w
when can we dance
Julian does a great job of explaining the way to deal with apostrophes in his answer above, but if you disregard their presence, I would use &. (Under) with ;: (Words) to sort them according to length after they are boxed and then unboxing them.
s=:'when can we dance'
(/: # each) &. ;: s
we can when dance
(/: # each) is the hook that orders them according to each length and &.;: boxes them and then at the end unboxes them to provide the result.

how to position a string character in R

Suppose I have a string like:
x<-c("bv_bid_bayley_inf_development_f7r","bv_fci_family_care_indicator_f7r")
how can I position the first "_" (a) and the last "_" (b) so that I can substr(x,a,b) in R. Such a output like that:
bid_bayley_inf_development
fci_family_care_indicator
You can use regular expressions to extract the substring:
x <- c("bv_bid_bayley_inf_development_f7r", "bv_fci_family_care_indicator_f7r")
sub("[^_]*_(.*)_[^_]*", "\\1", x)
# [1] "bid_bayley_inf_development" "fci_family_care_indicator"
for position only,
gregexpr("_",x)

How to efficiently interlace multiple groups of lines in Vim?

I am trying to interlace three groups of lines of text. For example, the following text:
a
a
a
b
b
b
c
c
c
is to be transformed into:
a
b
c
a
b
c
a
b
c
Is there an efficient way of doing this?
Somewhere in the depths of my ~/.vim files I have an :Interleave command (appended below). With out any arguments :Interleave will just interleave just as normal. With 2 arguments how ever it will specify how many are to be grouped together. e.g. :Interleave 2 1 will take 2 rows from the top and then interleave with 1 row from the bottom.
Now to solve your problem
:1,/c/-1Interleave
:Interleave 2 1
1,/c/-1 range starting with the first row and ending 1 row above the first line matching a letter c.
:1,/c/-1Interleave basically interleave the groups of a's and b's
:Interleave 2 1 the range is the entire file this time.
:Interleave 2 1 interleave the group of mixed a's and b's with the group of cs. With a mixing ratio of 2 to 1.
The :Interleave code is below.
command! -bar -nargs=* -range=% Interleave :<line1>,<line2>call Interleave(<f-args>)
fun! Interleave(...) range
if a:0 == 0
let x = 1
let y = 1
elseif a:0 == 1
let x = a:1
let y = a:1
elseif a:0 == 2
let x = a:1
let y = a:2
elseif a:0 > 2
echohl WarningMsg
echo "Argument Error: can have at most 2 arguments"
echohl None
return
endif
let i = a:firstline + x - 1
let total = a:lastline - a:firstline + 1
let j = total / (x + y) * x + a:firstline
while j < a:lastline
let range = y > 1 ? j . ',' . (j+y) : j
silent exe range . 'move ' . i
let i += y + x
let j += y
endwhile
endfun
Here is a "oneliner" (almost), but you have to redo it for every unique line minus 1, in your example 2 times. Perhaps of no use, but I think it was a good exercise to learn more about patterns in VIM. It handles all kind of lines as long as the whole line is unique (e.g. mno and mnp are two unique lines).
First make sure of this (and do not have / mapped to anything, or anything else in the line):
:set nowrapscan
Then map e.g. these (should be recursive, not nnoremap):
<C-R> and <CR> should be typed literally.
\v in patterns means "very magic", #! negative look-ahead. \2 use what's found in second parenthesis.
:nmap ,. "xy$/\v^<C-R>x$<CR>:/\v^(<C-R>x)#!(.*)$\n(\2)$/m-<CR>j,.
:nmap ,, gg,.
Then do ,, as many times as it takes, in your example 2 times. One for all bs and one for all cs.
EDIT: explanation of the mapping. I will use the example in the question as if it has run one time with this mapping.
After one run:
1. a
2. b
3. a
4. b
5. a
6. b
7. c
8. c
9. c
The cursor is then at the last a (line 5), when typing ,,, it first go back to first line, and then runs mapping for ,., and that mapping is doing this:
"xy$ # yanks current line (line 1) to reg. "x" ("a") "
/\v^<C-R>x$<CR> # finds next line matching reg. "x" ("a" at line 3)
:/\v^(<C-R>x)#!(.*)$\n(\2)$/m-<CR>
# finds next line that have a copy under it ("c" in line 7) and moves that line
# to current line (to line 3, if no "-" #after "m" it's pasted after current line)
# Parts in the pattern:
- ^(<C-R>x)#!(.*)$ # matches next line that don't start with what's in reg. "x"
- \n(\2)$ # ...and followed by newline and same line again ("c\nc")
- m-<CR> # inserts found line at current line (line 3)
j # down one line (to line 4, where second "a" now is)
,. # does all again (recursive), this time finding "c" in line 8
...
,. # gives error since there are no more repeated lines,
# and the "looping" breaks.
I just ran into this issue independently tonight. Mine's not as elegant as some of the answers, but it's easier to understand I think. It makes many assumptions, so it's a bit of a hack:
A) It assumes there's some unique character (or arbitrary character
string) not present in any of the lines - I assume # below.
B) It
assumes you don't want leading or trailing white space in any of the
a, b, or c sections.
C) It assumes you can easily identify the
maximum line length, and then pad all lines to be that length (e.g.
perhaps using %! into awk or etc., using printf)
Pad all lines with spaces to the same maximum length.
Visual Select just the a and b sections, then %s/$/#
Block copy and past the b section to precede the c section.
Block copy and paste the a section to precede the bc section.
%s/#/\r
%s/^ *//g
%s/ *$//g
delete the lines left where the a and b sections were.
If you have xclip you can cut the lines and use paste to interleave them:
Visual select one set of lines
Type "+d to cut them to the clipboard
Visual select the other set of lines
Type !paste -d '\n' /dev/stdin <(xclip -o -selection clipboard)
Put the following as interleave.awk in your path, make it executable.
#!/usr/bin/awk -f
BEGIN { C = 2; if (ARGC > 1) C = ARGV[1]; ARGV[1]="" }
{ g = (NR - 1) % C; if (!g) print $0; else O[g] = O[g] $0 "\n" }
END { for (i = 1; i < C; i++) printf O[i] }
Then from vim highlight the lines in visual mode, then call :'<,'>!interleave.awk 3, or replace 3 with however many groups to interleave (or leave blank for 2).
You asked for an efficient way. Interpreted languages aside, this may be the most efficient algorithm for interleaving arbitrary lines - the first group are immediately printed, saving some RAM. If RAM was at a premium (eg, massive lines or too many of them) you could instead store offsets to the start of each line, and if the lines had a consistent well defined length (at least within groups), you wouldn't even need to store offsets. However, this way the file is scanned only once (permitting use of stdin), and CPUs are fast at copying blocks of data, while file pointer operations probably each require a context switch as they would normally have to trigger a system call.
Perhaps most importantly, the code is simple and short - and efficiency of reading and implementation are usually the most important of all.
Edit: looks like others have come to the same solution - just found https://stackoverflow.com/a/16088069/118153 when reframing the question in a search engine to see if I'd missed something obvious.

How to paste two vectors together and pad at the end?

I would like to paste two character strings together and pad at the end with another character to make the combination a certain length. I was wondering if there was an option to paste that one can pass or another trick that I am missing? I can do this in multiple lines by figuring out the length of each and then calling paste with rep(my_pad_character,N) but I would like to do this in one line.
Ex: pad together "hi", and "hello" and pad with an "a" to make the sequence length 10. the result would be "hihelloaaa"
Here is one option:
s1 <- "hi"
s2 <- "hello"
f <- function(x, y, pad = "a", length = 10) {
out <- paste0(x, y)
nc <- nchar(out)
paste0(out, paste(rep(pad, length - nc), collapse = ""))
}
> f(s1, s2)
[1] "hihelloaaa"
You can use the stringr function str_pad
library(stringr)
str_pad(paste0('hi','hello'), side = 'right', width = 10 , pad = 'a')

Resources