Skip to content

Instantly share code, notes, and snippets.

@0racle
Last active June 2, 2025 02:47
Show Gist options
  • Save 0racle/91b63c16a15e16bc6ab5548a47fe1ccd to your computer and use it in GitHub Desktop.
Save 0racle/91b63c16a15e16bc6ab5548a47fe1ccd to your computer and use it in GitHub Desktop.
J Profile Definitions

Here's a rundown of definitions in my .jprofile.ijs, which get loaded in all J sessions.

Some of these are so simple they don't need names, but sometimes I just put things in here so I don't forget how to spell them.

Not all the functions are the most efficient, they're just there for playing with data. Often in a script, I will copy a function in, or re-write one that is more specific to the given problem domain.

Names

Alphanumerics

NB. AlphaNumerics             || Golf versions
azuc   =: (65 ,: 26) ];.0 a.  NB. u: 65 + i. 26
azlc   =: (97 ,: 26) ];.0 a.  NB. u: 97 + i. 26
digits =: (48 ,: 10) ];.0 a.  NB. u: 48 + i. 10
alnum  =: azuc,azlc,digits

These are useful in light string parsing, and also as test data

Functions

Visualise boolean arrays different ways

B =: 0&$: : {{
    B0 =. ((u: 183 9619) { ~ ])"2
    B1 =. (u: 16b20 16b2584 16b2580 16b2588) {~ (,:~2 1) #.@,;._3 ]
    B2 =. (,:~4 2) (10240 u:@+ 40283 #.@A. ,);._3 ]
    B3 =. ((u: 11036 11035) { ~ ])"2
    B0`B1`B2`B3@.x y
}}

I originally had just B defined like B0, but I then I nabbed the others from here.

Example usage

   B (<:/&i. -) 5
▓▓▓▓▓
▓▓▓▓·
▓▓▓··
▓▓···
▓····
   1 B (<:/&i. -) 10
█████████▀
███████▀
█████▀
███▀
█▀
   2 B (<:/&i. -) 20
⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋
⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀
⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀
⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀

Box and laminate arrays for comparison

Over =: (8!:1)@,:&(<"_1)

On =: {{
    x ((,:&(<"_1))`((,~ <"_1)~)@.(32 = (3!:0) {. y)) y
}}

Over is a convenience function for comparing 2 arrays that may be of different types (hence the boxing).

Similar to the ,[0.5] thingy in APL.

   (Over azlc&i.) 'alphabetical'
┌─┬──┬──┬─┬─┬─┬─┬──┬─┬─┬─┬──┐
│a│l │p │h│a│b│e│t │i│c│a│l │
│0111570141982011│
└─┴──┴──┴─┴─┴─┴─┴──┴─┴─┴─┴──┘
   (Over B@e.&'aeiou') 'iversonian'
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│i│v│e│r│s│o│n│i│a│n│
│▓│·│▓│·│·│▓│·│▓│▓│·│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘

On is a more heavy-weight version that doesn't format the output, and can stack multiple lists

   (i. 4) On 'RULD' On (, -) =/~ i. 2
┌───┬───┬────┬────┐
│0123   │
├───┼───┼────┼────┤
│R  │U  │L   │D   │
├───┼───┼────┼────┤
│1 00 1_1 00 _1│
└───┴───┴────┴────┘

I use Over more, so I should probably swap the names around 🤷

Extract numeric values from string

For ℕatural numbers (well... Whole numbers, cos 0, but I like the name Nats)

Nats =: '1234567890'&(i. ".@:{ ' ',~ [)

Or for (possibly negative) floats

Nums =: '1234567890._ '  ".@:{~ '1234567890.-' i. ]

Pass a string with something separating the numbers

   */ Nats '175m × 50m'
8750
   Nums '12 + -3 == 9'
12 _3 9

Partition adverb similar to APL's

P =: {{ (1, 2 </\ x) u;.1&(x&#) y }}

This closely mimics the APL operator, and - among other uses - can also be used to extract numbers from a string.

   digits (e.~ <P ]) '175m × 50m'
┌───┬──┐
│17550│
└───┴──┘
   */ digits (e.~ ".P ]) '175m × 50m'
8750

See this gist for more examples.

Extended E.

Credit to @tubular on 'The APL Farm' Discord for this

E =: +./@(-@(#: [: i. */)@$@[ |. E.)

Like E. but the resulting mask include the whole match (not just the upper left corner), with possible overlaps

   < B ('ab',:'ba') E 'ab' {~ ? 10 20 $ 2
┌────────────────────┐
│····················│
│········▓▓··········│
│········▓▓··········│
│··············▓▓····│
│▓▓···▓▓·····▓▓▓▓····│
│▓▓··▓▓▓·····▓▓▓▓▓···│
│····▓▓·······▓▓▓▓···│
│·········▓▓·▓▓······│
│·········▓▓▓▓▓······│
│···········▓▓·······│
└────────────────────┘

Extract runs from a sequence

Runs =: {{ y u;.1~ 1, 2 ~:/\ v y }}

Conjunction for processing "runs" of values.

  • v defines how to identify runs,
  • u defines what to do with those runs
   <Runs] 'aabcccaaaaabbbc'
┌──┬─┬───┬─────┬───┬─┐
│aa│b│ccc│aaaaa│bbb│c│
└──┴─┴───┴─────┴───┴─┘
   #Runs] 'aabcccaaaaabbbc'
2 1 3 5 3 1
   <Runs('a'=]) 'aabcccaaaaabbbc'
┌──┬────┬─────┬────┐
│aa│bccc│aaaaa│bbbc│
└──┴────┴─────┴────┘

If you don't care about false runs, use P

   (('a'=]) <P ]) 'aabcccaaaaabbbc'
┌──┬─────┐
│aa│aaaaa│
└──┴─────┘

Modify values in an array with a function

Adjust =: (@:{)`[`]}    NB. {{ (u x { y) x} y }}

Alter =: {{ (($ <@#: I.@,)^:(1 < #@$) x) u Adjust y }}

Adjust is Like Amend } but takes a function to modify selected items

   2 3 (*&10) Adjust i.  6
0 1 20 30 4 5
   ] a =. 1 (< ;~ i. 3)} 5 5 $ 0
1 1 1 0 0
1 1 1 0 0
1 1 1 0 0
0 0 0 0 0
0 0 0 0 0
   (<1 2 3;1 2 3) (1 XOR ]) Adjust a
1 1 1 0 0
1 0 0 1 0
1 0 0 1 0
0 1 1 1 0
0 0 0 0 0

Alter is a similar function which takes a mask instead of indices

This is kinda like BQN's "Under Select" {𝔽⌾(𝕨⊸/)𝕩}

   0 1 1 0 0 toupper Alter 'alter'
aLTer
   (];.0 a) (1 XOR ]) Alter a
1 1 1 0 0
1 1 1 0 0
1 1 0 1 1
0 0 1 1 1
0 0 1 1 1

Amend. Adjust. Alter. Yes, I used a thesaurus.

Insert values (splice)

Insert =: {{ m ({. , x , }.) y }}

Inserts x in y, at position m

   'Three' 6 Insert 'OneTwoFour'
OneTwoThreeFour

Shuffle array

Shuffle =: $ $ ({~ ?~@#)@,

Randomises position of all items in a matrix across ranks.

Use it with Rank " to limit it's effect

   <"_1 Shuffle i. 2 2 3
┌───────┬─────┐
│5 10 117 8 1│
│0  4  96 3 2│
└───────┴─────┘
   <"_1 Shuffle"1 i. 2 2 3
┌─────┬───────┐
│1 0 26 7  8│
│3 5 411 9 10│
└─────┴───────┘
   <"_1 Shuffle"_1 i. 2 2 3
┌─────┬───────┐
│3 5 411 8  9│
│1 0 26 7 10│
└─────┴───────┘

Indices inverse

Iinv =: <:@#/.~@(,~ i.@>:@(>./))

NB. I.^:_1 (or I.inv) is now availble since J9.6.0-beta5, but leaving it here in case I need it on the Playground or something.

   ] p =. /:~ 10 ? 20
1 5 6 7 8 9 10 11 15 17
   Iinv p
0 1 0 0 0 1 1 1 1 1 1 1 0 0 0 1 0 1
   I. Iinv p
1 5 6 7 8 9 10 11 15 17

Consecutive integers from x to y (inclusive)

To =: ([ + i.@(>:@-~))`(|.@$:~)@.>

Return a [closed, closed] range from x to y, either ascending or descending.

   _3 To 11
_3 _2 _1 0 1 2 3 4 5 6 7 8 9 10 11
   11 To _3
11 10 9 8 7 6 5 4 3 2 1 0 _1 _2 _3

If I want [closed, open), I can always just }:

Three-way comparison

Cmp =: {.@(/: - \:)@,&<

Get single "order" - like < or > - but on Array

   1 2 3 Cmp 1 3 2
_1
   'alpha' Cmp 'beta'
_1
   'gamma' Cmp 'beta'
1

Odometer monad

Odm =: #: ,@i.

Like K's !

   |: Odm 3 3
0 0 0 1 1 1 2 2 2
0 1 2 0 1 2 0 1 2

Iota monad

Iota =: #: i.

Like APL's or BQN's , given multiple values

   <"1 Iota 3 3
┌───┬───┬───┐
│0 00 10 2│
├───┼───┼───┤
│1 01 11 2│
├───┼───┼───┤
│2 02 12 2│
└───┴───┴───┘

Left-shift and Right-shift

Ls =: ($:~ (0 {.@$ ])) : (-@#@] {. ,~)
Rs =: ($:~ (0 {.@$ ])) : (  #@] {. , )

Mimicks BQN's « and »

   'w' Rs 'hat'
'wha'

Aliases

Some shorter (possibly inverse-able) versions of existing functions.

Ord =: (u:^:_1) :. (u:)
Chr =: (u:) :. (u:^:_1)

Uc  =: toupper :. tolower
Lc  =: tolower :. toupper

NB. Left-shift and Right-shift
Ls  =: (1&$:) : (|.!.'')
Rs  =: Ls&.|.

Time & Space

ts =: {{
    echo < dtbs,/ 'timespacex × ',('c' (8!:2) x)
    result =. x&{{ y ; (8!:0) (x, 1) * x timespacex y }}@> cutopen y
    echo ,. ('expr';'time';'space') , result
}}

A subjectively prettier timespacex

   1e6 ts '> , { ;~ i: 1';',/ ,"0/~ i: 1'
┌──────────────────────┐
│timespacex × 1,000,000│
└──────────────────────┘
┌─────────────┬────────┬─────┐
│expr         │time    │space│
├─────────────┼────────┼─────┤
│> , { ;~ i: 11.8347013520 │
├─────────────┼────────┼─────┤
│,/ ,"0/~ i: 11.3897052880 │
└─────────────┴────────┴─────┘

Datetime conversion

Now =: 6!:0
Timer =: 6!:1

cocurrent 'epoch'
ToEpoch   =: 1e3  %~ 5364662400000 -~ tsrep
FromEpoch =: 1 tsrep 5364662400000 + 1e3 * ]
cocurrent 'base'
ToEpoch =: ToEpoch_epoch_ :. FromEpoch_epoch_
FromEpoch =: FromEpoch_epoch_ :. ToEpoch_epoch_

Just some aliases, and some invertable time conversion verbs

   ] t =. Now ''
2025 6 2 12 26 45.2506
   (106425 + ])&.ToEpoch t
2025 6 3 18 0 30.2506

I use Timer sometimes to show running time, eg.

start =. Timer ''
res =. SlowVerb y
echo start -~ Timer ''

File / Path stuff

curfile =: {{ _1 {:: (4!:3) $ 0 }}
curpath =: ] ,~ 0 {:: fpathname@curfile
chdir   =: (1!:44)

The cur* verbs are probably not 100% reliable but works for my use case. Probably named poorly, because it's not cwd. Maybe should be scriptpath, but whatever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment