Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h3>bottom line</h3> <p>Here's a little utility you can put in your toolbox:</p> <pre><code> tr =: dyad def '(y i.~ ({." 1 x),y) { ({:" 1 x) , y' ] MAP =: _2 ]\ 'a';3; 'b';4 +-+-+ |a|3| +-+-+ |b|4| +-+-+ MAP tr 'a';'b';'c';'a';'b';'a' +-+-+-+-+-+-+ |3|4|c|3|4|3| +-+-+-+-+-+-+ </code></pre> <h3>just above the bottom line</h3> <p>The utility <code>tr</code> is a verb which takes two arguments (a dyad): the right argument is the target, and the left argument is the mapping table. The table must have two columns, and each row represents a single mapping. To make just a single replacement, a vector of two items is acceptable (i.e. 1D list instead of 2D table, so long as the list is two items long).</p> <p>Note that the table must have the same datatype as the target (so, if you're replacing boxes, it must be a table of boxes; if characters, then a table of characters; numbers for numbers, etc). </p> <p>And, since we're doing like-for-like mapping, the cells of the mapping table must have the same <em>shape</em> as the items of the target, so it's not suitable for tasks like string substitution, which may require shape-shifting. For example, <code>('pony';'horse') tr 'I want a pony for christmas'</code> won't work (though, amusingly, <code>'pony horse' tr&amp;.;: 'I want a pony for christmas'</code> would, for reasons I won't get into).</p> <h3>way above the bottom line</h3> <p>There's no one, standard answer to your question. That said, there is a very common idiom to do translation (in the <code>tr</code>, or mapping 1:1, sense):</p> <pre><code> FROM =: ;: 'cat dog bird' TO =: ;: 'tiger wolf pterodactyl' input=: ;: 'cat bird dog bird bird cat' (FROM i. input) { TO +-----+-----------+----+-----------+-----------+-----+ |tiger|pterodactyl|wolf|pterodactyl|pterodactyl|tiger| +-----+-----------+----+-----------+-----------+-----+ </code></pre> <p>To break this down, the primitive <code>i.</code> is the lookup function and the primitive <code>{</code> is the selection function (mnemonic: <code>i.</code> gives you the *<em>i</em>*ndex of the elements you're looking for). </p> <p>But the simplistic formulation above only applies when you want to replace literally everything in the input, and <code>FROM</code> is guaranteed to be total (i.e. the items of the input are constrained to whatever is in <code>FROM</code>).</p> <p>These contraints make the simple formulation appropriate for tasks like case conversion of strings, where you want to replace all the letters, and we know the total universe of letters in advance (i.e. the alphabet is finite).</p> <p>But what happens if we don't have a finite universe? What should we do with unrecognized items? Well, anything we want. This need for flexibility is the reason that there is no one, single translation function in J: instead, the language gives you the tools to craft a solution specific to your needs.</p> <p>For example, one very common extension to the pattern above is the concept of substitution-with-default (for unrecognized items). And, because <code>i.</code> is defined to return <code>1+#input</code> for items not found in the lookup, the extension is surprisingly simple: we just extend the replacement list by one item, i.e. just append the default!</p> <pre><code> DEFAULT =: &lt;'yeti' input=: ;: 'cat bird dog horse bird monkey cat iguana' (FROM i. input) { TO,DEFAULT +-----+-----------+----+----+-----------+----+-----+----+ |tiger|pterodactyl|wolf|yeti|pterodactyl|yeti|tiger|yeti| +-----+-----------+----+----+-----------+----+-----+----+ </code></pre> <p>Of course, this is destructive in the sense it's not invertible: it leaves no information about the input. Sometimes, as in your question, if you don't know how to replace something, it's best to leave it alone.</p> <p>Again, this kind of extension is surprisingly simple, and, once you see it, obvious: you extend the lookup table <em>by appending the input</em>. That way, you're guaranteed to find all the items of the input. And replacement is similarly simple: you extend the replacement list <em>by appending the input</em>. So you end up replacing all unknown items with themselves. </p> <pre><code> ( (FROM,input) i. input) { TO,input +-----+-----------+----+-----+-----------+------+-----+------+ |tiger|pterodactyl|wolf|horse|pterodactyl|monkey|tiger|iguana| +-----+-----------+----+-----+-----------+------+-----+------+ </code></pre> <p>This is the strategy embodied in <code>tr</code>. </p> <h3>above the top line: an extension</h3> <p>BTW, when writing utilities like <code>tr</code>, J programmers will often consider the N-dimensional case, because that's the spirit of the language. As it stands, <code>tr</code> requires a 2-dimensional mapping table (and, by accident, will accept a 1-dimensional list of two items, which can be convenient). But there may come a day when we want to replace a plane inside a cube, or a cube inside a hypercube, etc (common in in business intelligence applications). We may wish to extend the utility to cover these cases, should they ever arise.</p> <p>But how? Well, we know the mapping table must have <em>at least</em> two dimensions: one to hold multiple simultaneous substitutions, and another to hold the rules for replacement (i.e. one "row" per substition and two "columns" to identify an item and its replacement). The key here is that's <em>all</em> we need. To generalize <code>tr</code>, we merely need to say we <em>don't care</em> about what's beneath those dimensions. It could be a Nx2 table of single characters, or an Nx2 table of fixed-length strings, or an Nx2 table of matrices for some linear algebra purpose, or ... who cares? Not our problem. We only care about the frame, not the contents.</p> <p>So let's say that, in <code>tr</code>:</p> <pre><code> NB. Original tr =: dyad def '(y i.~ ({." 1 x),y) { ({:" 1 x) , y' NB. New, laissez-faire definition tr =: dyad def '(y i.~ ({."_1 x),y) { ({:"_1 x) , y' </code></pre> <p>A taxing change, as you can see ;). Less glibly: the rank operator <code>"</code> can take positive or negative arguments. A positive argument lets the verb address the <em>content</em> of its input, whereas a negative argument lets the verb address the <em>frame</em> of its input. Here, <code>"1</code> (positive) applies <code>{.</code> to the rows of the <code>x</code>, whereas <code>"_1</code> (negative) applies it to the the "rows" of <code>x</code>, where "rows" in scare-quotes simply means the items along the first dimension, even if they happen to be 37-dimensional hyperrectangles. Who cares?</p> <p>Well, one guy cares. The original definition of <code>tr</code> let the laziest programmer write <code>('dog';'cat') tr ;: 'a dog makes the best pet'</code> instead of <code>(,:'dog';'cat') tr ;: 'a dog makes the best pet'</code>. That is, the original <code>tr</code> (completely accidentally) allowed a simple list as a mapping table, which of course isn't a Nx2 table, even in an abstract, virtual sense (because it doesn't have <em>at least</em> two dimensions). Maybe we'd like to retain this convenience. If so, we'd have to promote degenerate arguments on the user's behalf:</p> <pre><code>tr =: dyad define x=.,:^:(1=#@$) x (y i.~ ({."_1 x),y) { ({:"_1 x) , y ) </code></pre> <p>After all, laziness is a <a href="http://www.c2.com/cgi/wiki?LazinessImpatienceHubris" rel="nofollow">prime virtue of a programmer</a>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload