1 title:: J concepts in SC
2 summary:: An overview of concepts borrowed from J
5 The J programming language is a successor of APL (http://www.jsoftware.com). These languages are made for processing arrays of data and are able to express
6 complex notions of iteration implicitly.
8 The following are some concepts borrowed from or inspired by J.
9 Thinking about multidimensional arrays can be both mind bending and mind expanding.
10 It may take some effort to grasp what is happening in these examples.
12 section:: Filling arrays
13 iota fills an array with a counter
15 z = Array.iota(2, 3, 3);
16 z.rank; // 3 dimensions
17 z.shape; // gives the sizes of the dimensions
18 z = z.reshape(3, 2, 3); // reshape changes the dimensions of an array
19 z.rank; // 3 dimensions
23 fill a multidimensional array
26 Array.fill([3,3], { 1.0.rand.round(0.01) });
27 Array.fill([2,3], {|i,j| i@j });
30 Array.fill([2, 2, 2], { 1.0.rand.round(0.01) });
31 Array.fill([2, 3, 4], {|i,j,k| [i, j, k].join });
33 // a shorter variant of the above:
34 {|i,j,k| [i, j, k].join } ! [2, 3, 4];
37 Array.fill([2, 2, 4, 2], {|...args| args.join });
41 section:: Creating arrays
42 using dup to create arrays
47 {100.rand} dup: 3 dup: 4;
48 {{100.rand} dup: 3} dup: 4;
49 {|i| i.squared} dup: 10;
50 {|i| i.nthPrime} dup: 10;
51 { |i, j, k| i * j } dup: [5, 5]; // multidimensional dup
53 ! is an abbreviation of dup
61 {|i| i.nthPrime} ! 10;
62 { |i, j| i * j } ! [5, 5];
65 other ways to do the same thing:
67 // partial application
71 // operating on a list
76 section:: Operator adverbs
77 Adverbs are a third argument passed to binary operators that modifies how they iterate over
78 SequenceableCollections or Streams. See the link::Reference/Adverbs:: help file for more information.
80 [10, 20, 30, 40, 50] + [1, 2, 3]; // normal
81 [10, 20, 30, 40, 50] +.f [1, 2, 3]; // folded
82 [10, 20, 30, 40, 50] +.s [1, 2, 3]; // shorter
83 [10, 20, 30, 40, 50] +.x [1, 2, 3]; // cross
84 [10, 20, 30, 40, 50] +.t [1, 2, 3]; // table
87 section:: Operator depth
88 J has a concept called verb rank, which is probably too complex to understand and implement in SC, but operator depth is similar and simpler.
89 A binary operator can be given a depth at which to operate. Negative depths iterate the opposite operand.
90 These are better understood by example. It is not currently possible to combine adverb and depth.
95 z +.0 y; // same as the above. y added to each row of z
96 z +.1 y; // y added to each column of z
97 z +.2 y; // y added to each element of z
98 z +.-1 y; // z added to each element of y
101 subsection:: deepCollect
102 deepCollect operates a function at different dimensions or depths in an array.
104 z = Array.iota(3, 2, 3);
105 f = {|item| item.reverse };
110 f = {|item| item.stutter };
116 section:: Sections of multidimensional arrays
117 slice can get sections of multidimensional arrays.
118 nil gets all the indices of a dimension.
120 z = Array.iota(4, 5);
121 z.slice(nil, (1..3));
123 z.slice((2..3), (0..2));
127 z = Array.iota(3, 3, 3);
128 z.slice([0,1], [1,2], [0,2]);
129 z.slice(nil, nil, [0,2]);
132 z.slice(nil, nil, 1);
134 z.slice(nil, 1, (1..2));
139 section:: Sorting order
140 generate a random array:
142 z = {100.rand}.dup(10);
144 order returns an array of indices representing what would be the sorted order of the array:
147 y = z[o]; // using the order as an index returns the sorted array
149 calling order on the order returns an array of indices that returns the sorted array to the
150 original scrambled order:
157 bubbling wraps an item in an array of one element. it takes the depth and levels as arguments.
167 similarly, unbubble unwraps an Array if it contains a single element.
175 [[4],[5]].unbubble(1);
177 z.bubble(1).unbubble(1);
178 z.bubble(2).unbubble(2);
181 section:: Laminating with the +++ operator
182 the +++ operator takes each item from the second list and appends it to the corresponding item
183 in the first list. If the second list is shorter, it wraps.
188 z +++ [[[77,88,99]]];
189 z +++ [ [[77]],[[88]],[[99]] ];
191 z +++ [77,88,99].bubble;
192 z +++ [77,88,99].bubble(0,2);
193 z +++ [77,88,99].bubble(1,2);
195 z +++ [11,22,33].pyramidg;
196 z +++ [11,22,33].pyramidg.bubble;
197 z +++ [[11,22,33].pyramidg];
198 z +++ [[[11,22,33].pyramidg]];
204 z.pyramid(i+1).postln;
205 z.pyramidg(i+1).postln;
211 section:: reshapeLike
212 reshapeLike allows you to make one nested array be restructured in the same manner as another.
214 a = [[10,20],[30, 40, 50], 60, 70, [80, 90]];
215 b = [[1, 2, [3, 4], [[5], 6], 7], 8, [[9]]];
219 If the lengths are different, the default behaviour is to wrap:
221 a = [[10,20],[30, 40, 50]];
222 b = [[1, 2, [3, 4], [[5], 6], 7], 8, [[9]]];
225 but you can specify other index operators:
227 a.reshapeLike(b, \foldAt);
229 a.reshapeLike(b, \clipAt);
231 a.reshapeLike(b, \at);
234 section:: measuring dimensionality and size
235 maxSizeAtDepth allows you to check the maximum array size at a given depth dimension
237 [[1, 2, 3], [[41, 52], 5, 6], 1, 2, 3].maxSizeAtDepth(2);
238 [[1, 2, 3], [[41, 52], 5, 6], 1, 2, 3].maxSizeAtDepth(1);
239 [[1, 2, 3], [[41, 52], 5, 6], 1, 2, 3].maxSizeAtDepth(0);
240 (0..3).collect([[1, 2, 3], [[41, 52], 5, 6], 1, 2, 3].maxSizeAtDepth(_)) // max sizes for each dimension
243 section:: inverting dimensions
244 flopDeep allows you to to invert the outermost dimension with a dimension at any depth. This is analogous to flop, which does the same for 2-dimensional arrays.
246 [[1, 2, 3], [[41, 52], 5, 6]].flopDeep(2);
247 [[1, 2, 3], [[41, 52], 5, 6]].flopDeep(1);
248 [[1, 2, 3], [[41, 52], 5, 6]].flopDeep(0);
249 [[1, 2, 3], [[41, 52], 5, 6]].flopDeep; // without argument, flop from the deepest level
251 [[[10, 100, 1000], 2, 3], [[41, 52], 5, 6]].flopDeep(2); // shorter array wraps
252 [].flopDeep(1); // result is always one dimension higher.
258 allTuples will generate all combinations of the sub arrays
260 [[1, 2, 3], [4, 5], 6].allTuples;
261 [[1, 2, 3], [4, 5, 6, 7], [8, 9]].allTuples;