Ops
One reason why iogii really is simple is that most ops are completely trivial and don't have any special cases. You can know everything there is to know just by looking at their name, type, and example.
This is a catalog of all ops that aren't already completely obvious from their quickref description.
Reshape
Take n elements from a list, then recurse on that many elements dropped. n will typically be the same number and hence the second arg is repeated instead of promoted so that you can provide a list instead (see Nitty Gritty:special reptitions).
Typical usage:
"abcdef" 2 reshape → ["ab","cd","ef"]
↗️
But you can take different numbers of elements at each step:
"abcdef" 1,2,3 reshape → ["a","bc","def"]
↗️
You can even take 0 elements (negative is treated as 0 also).
"abcdef" 3,0,3 reshape → ["abc","","def"]
↗️
If it ever tries to take more than there is, then it will terminate, returning what it found so far.
"abcdef" 4 reshape → ["abcd","ef"]
↗️
Trailing 0s will work if it didn't try to previously take more than there was:
"abcdef" 6,0,0,1 reshape → ["abcdef","",""]
↗️
If the second arg ends then the results end too:
"abcdef" 2,2 reshape → ["ab","cd"]
↗️
I was inspired by the mold sort challenge to make sure that trailing 0s work. This somewhat felt like cheating, but really this is the most intuitive behavior for the op. It takes hands on experience to truly understand how to make ops as general as possible, and I'm sure I haven't perfected every op. If you ever wish an op was a bit different and think it is an overall improvement you can cheat too! Let me know!
Transpose
You can transpose a list of different length lists, it will fill in missing values with the default value for that type:
"abcd","ef","1234" transpose → ["ae1","bf2","c 3","d 4"]
↗️
But it will truncate instead if there are no more values after a point:
"abc","1" transpose → ["a1","b","c"]
↗️
Get
get
returns the ith element (0 indexed) or the default value for the type if out of bounds. Special behavior for negatives or out of bounds is likely less useful since it can be simulated using reverse
or repeat concat
.
SetDiff
setDiff
removes the elements of the second arg from the first. If there are two occurrences of an element it will remove up to two of that element from the first, and so on for higher counts.
SortBy
It is stable and O(n log n).
Read / ReadAll
These ops ignore all non numbers and leading negative signs to return parsed numbers from a string. read
is just the head
of readAll
.
read
will return 0 if no numbers are present, if you wanted to detect that you could check the length of readAll
.
Join
If you join a string (instead of a list of strings), it promotes each character to a string (rather an unvectorized promote which would be useless here).
"abc" " " * → "a b c"
↗️
ChunkWhen
This op is likely to be rarely used, but very useful when it is, and it is the only op that can allow you to split a list up by an arbitrary criteria. (Besides doing it manually which seems difficult). I have gone through several variations of this op over the years and settled on the current behavior as the most versatile and easy to use. You can accomplish things like grouping truthy elements together (removing falsey) and grouping adjacent equal elements very easily with this op.
It splits the first list after each falsey value from the second list.
"abcd" 1,0,1,1 chunkWhen → ["ab","cd"]
↗️
Because the value corresponding to 'b
is 0, it split after that value.
Note that the last 1
is the op stops splitting when the second arg runs out and returns the remaining list of the first arg.
"abcd" 1,0,1 chunkWhen → ["ab","cd"]
↗️
But if the last value had instead been a 0, that would indicate the next list has started, so the behavior would be different:
"abcd" 1,0,1,0 chunkWhen → ["ab","cd",""]
↗️
Extra condition values are also ignored.
"ab" 1,1,1,1 chunkWhen → ["ab"]
"ab" 0,0,0,0 chunkWhen → ["a","b",""]
And as promised, here is how we could group truthy values:
"ab bc"; consDefault chunkWhen tail → ["ab","bc"]
↗️
The consDefault
is necessary to align things correctly (but the value is ignored by the later tail
). If you wanted to provide custom truhty behavior, just modify the duplicated value after the consDefault
.
This will return empty lists if multiple falsey values are present in a row (just filter if you don't want those).
And here's how we could group adjacent equal elements (similarly you could also define equality differently by doing something after the dup :
):
"aabbcdee" ::tail equal chunkWhen → ["aa","bb","c","d","ee"]
"abbcde" ::tail equal chunkWhen → ["a","bb","c","d","e"]