Convert boxed array to normal array? - j

Suppose I have a boxed array like;
┌─┬─┬─┐
│1│2│3│
└─┴─┴─┘
how do I covert it to a normal array such as 1 2 3?

Your example is not clear enough to specify exactly what is the wanted behavior on higher-dimension arrays. Thus there will be two solutions, which are the most commonly wanted behaviors in this kind of situations.
The first solution is to use the builtin monadic verb raze ;, as such
]a=.<"(0) 1+i.3
+-+-+-+
|1|2|3|
+-+-+-+
;a
1 2 3
Pretty straightforward. However, it should be noted that raze has rank _, and that it will always produce a list, that is, it will also flatten your array:
]a=.<"(0) 1+i.2 3
+-+-+-+
|1|2|3|
+-+-+-+
|4|5|6|
+-+-+-+
;a
1 2 3 4 5 6
If you don't want that behavior, you can always use the rank conjunction ":
;"1 a
1 2 3
4 5 6
Alternatively, you may also want to preserve the original shape of the array, in which case the monadic verb open > is probably what you want:
]a=.<"(0) 1+i.3
+-+-+-+
|1|2|3|
+-+-+-+
>a
1 2 3
]a=.<"(0) 1+i.2 3
+-+-+-+
|1|2|3|
+-+-+-+
|4|5|6|
+-+-+-+
>a
1 2 3
4 5 6
Finally, you should know that it's not necessary to create an array of unboxed values to operate on them, as creating this array may lead to unwanted behavior (especially with padding):
]a=.1 2;3 4 5
+---+-----+
|1 2|3 4 5|
+---+-----+
>a
1 2 0
3 4 5
Suppose I'd want to add 1 to each atom inside the boxes of a. Opening a won't do, as that will create an additional element 0 that is required for padding, which won't be removed if I rebox the lists afterwards
<"1>a
+-----+-----+
|1 2 0|3 4 5|
+-----+-----+
a -: <"1>a
0
Instead, I can modify my verb "add 1" to work on boxes instead, with the conjunction under (dual) &.
a=.1 2;3 4 5
1&+&.>a
+---+-----+
|2 3|4 5 6|
+---+-----+
Note that there is no extra padding!

Related

tabulate frequency counts including zeros

To illustrate the problem, consider the following data: 1,2,3,5,3,2. Enter this in a spreadsheet column and make a pivot table displaying the counts. Making use of the information in this pivot table, I want to create a new table, with counts for every value between 1 and 5.
1,1
2,2
3,2
4,0
5,1
What is a good way to do this? My first thought was to use VLOOKUP, trapping any lookup error. But GETPIVOTDATA is apparently preferred for pivot tables. In any case, I failed with both approaches.
To be a bit more specific, assume my pivot table of counts is "PivotTable1" and that I have already created a one column table holding all the needed lookup keys (i.e., the numbers from 1 to 5). What formula should I put in the second column of this new table?
So starting with this:
To illustrate the problem, consider the following data: 1,2,3,5,3,2. Enter this in a spreadsheet column and make a pivot table displaying the counts.
I then created the table like this:
X | Freq
- | ---------------------------------------------
1 | =IFERROR(GETPIVOTDATA("X",R3C1,"X",RC[-1]),0)
2 | =IFERROR(GETPIVOTDATA("X",R3C1,"X",RC[-1]),0)
3 | =IFERROR(GETPIVOTDATA("X",R3C1,"X",RC[-1]),0)
4 | =IFERROR(GETPIVOTDATA("X",R3C1,"X",RC[-1]),0)
5 | =IFERROR(GETPIVOTDATA("X",R3C1,"X",RC[-1]),0)
Or, in A1 mode:
X | Freq
- | -----------------------------------------
1 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",F3),0)
2 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",F4),0)
3 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",F5),0)
4 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",F6),0)
5 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",F7),0)
The column X in my summary table is in column F.
Or as a table formula:
X | Freq
- | -------------------------------------------
1 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",[#X]),0)
2 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",[#X]),0)
3 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",[#X]),0)
4 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",[#X]),0)
5 | =IFERROR(GETPIVOTDATA("X",$A$3,"X",[#X]),0)
That gave me this result:
X | Freq
- | ----
1 | 1
2 | 2
3 | 2
4 | 0
5 | 1
If performance is not a major concern, you can bypass the pivot table and use the COUNTIF() function.
Create a list of all consecutive numbers that you want the counts for and use COUNTIF() for each of them with the first parameter being the range of your input numbers and the second being the number of the ordered result list:
A B C D
1 1 1 =COUNTIF(A:A,C1)
2 2 2 =COUNTIF(A:A,C2)
3 3 3 =COUNTIF(A:A,C3)
4 5 4 =COUNTIF(A:A,C4)
5 3 5 =COUNTIF(A:A,C5)
6 2

List for minimum of corresponding columns excel

I have four columns with numbers. I would like to calculate in a separate cell a a sum. The sum will consist of the minimums of corresponding cells in these four columns
Example:
A | B | C | D
------------------
[1] 1 | 2 | 3 | 2
[2] 4 | 3 | 1 | 6
[3] 0 | 1 | 8 | 2
[4] 5 | 5 | 2 | 2
I need a formula that would calculate in a cell the sum of 1 + 1 + 0 + 2 where
I would like to use an array formula to do this calculation, but cannot figure out how to use minimum to accept arrays and return an array of minimums.
Thanks!
Assuming that data is in A1:D4:
SUBTOTAL(5,OFFSET(A1:D1,ROW(A1:D4)-MIN(ROW(A1:D4)),))
will give you the required, intermediate array to be used in further constructions as you see fit (with the caveat that that construction is one which is capable of coercing the necessary array from the above, of course).
Regards

Excel, Libreoffice/Openoffice Calc: count 'right' answers

I have a table with students' answers to 20 math problems like this:
A | B | C | D | E |...
------------+-----+-----+-----+-----+...
problem no | 1 | 2 | 3 | 4 |...
------------+-----+-----+-----+-----+...
right answer| 3 | 2 | A | 15 |...
------------+-----+-----+-----+-----+...
student1 | 3 | 4 | A | 12 |...
student2 | 2 | 2 | C | 15 |...
student3 | 3 | 2 | A | 13 |...
Now a need a column that counts the 'right' answers for each student.
I can do it this so: =(IF(D$3=D5;1;0))+(IF(E$3=E5;1;0))+(IF(F$3=F5;1;0))+...
...but it's not the nicest way :)
This is a typical use case for SUMPRODUCT:
A B C D E F G
1 problem no 1 2 3 4
2 right answer 3 2 A 15 right answers per student
3 student1 3 4 A 12 2
4 student2 2 2 C 15 2
5 student3 3 2 A 13 3
Formula in G3:
=SUMPRODUCT($B$2:$E$2=$B3:$E3)
If there are more problem numbers, then the column letters in $E$2 and $E3 have to be increased.
How it works:
SUMPRODUCT takes its inner functions as array formulas. So the $B$2:$E$2=$B3:$E3 becomes a matrix of {TRUE, FALSE, TRUE, FALSE} depending of if $B$2=$B3, $C$2=$C3, $D$2=$D3, $E$2=$E3.
In Libreoffice or Openoffice TRUE is 1 and FALSE is 0. So the SUMPRODUCT sums all TRUEs.
In Excel you have to get the boolean values in numeric context first. So the Formula in Excel will be =SUMPRODUCT(($B$2:$E$2=$B3:$E3)*1).
The formula in Row 3 then can be filled down for all student rows. The $ before the row number 2 ensures that thereby the row of the right answers not changes.
Greetings
Axel

slicing table into two parts and box it afterwards

I have a table like the following
0 1 2 3
4 5 6 7
8 9 10 11
and I want to make the following structure.
┌──────┬──┐
│0 1 2│ 3│
│4 5 6│ 7│
│8 9 10│11│
└──────┴──┘
Could anyone please help me?
And in J there is always another way!
]a=. i. 3 4
0 1 2 3
4 5 6 7
8 9 10 11
('' ;1 0 0 1) <;.1 a
┌──────┬──┐
│0 1 2│ 3│
│4 5 6│ 7│
│8 9 10│11│
└──────┴──┘
This uses the dyadic cut conjunction (;.) with the general form of x u ;. n y
y is the argument that we would like to partition, x specifies where the partitions are to be put, n is positive if we would like the frets (the partition positions) included in the result and a value of 1 means that we work from left to right, and u is the verb that we would like to apply to the partition.
One tricky point:
x is ('';1 0 0 1) because we want the entire first dimension of the array (rows) after which the 1's indicate the partition start. In this case we take all the rows and make the first partition the first 3 columns, and the final 1 makes the last partition its own column.
There is much going on in this solution, and that allows it to be used in many different ways, depending on the needs of the programmer.
The title of your question ("slicing table into two parts and box it afterwards") suggests that the example you sketch may not reflect what you want to learn.
My impression is that you think of your resulting noun as a two-axis table boxed into two sections. The main problem with that interpretation is that boxes divide their contents very thoroughly. It takes special effort to make the numbers in your second box look like they've been trimmed from the structure in the first box. Such effort is rarely worthwhile.
If it is natural to need to take the 3 7 11 and remove it as a unit from the structure in which it occurs, there is an advantage to making it a row of the table, rather than a column. A 2-axis table is always a list of 1-axis lists. If your problem is a matter of segregating items, this orientation of the atoms makes it simpler to do.
Putting this into practice, here we deal with rows instead of columns:
aa=: |:i.3 4
aa
0 4 8
1 5 9
2 6 10
3 7 11
(}: ; {:) aa
+------+------+
|0 4 8|3 7 11|
|1 5 9| |
|2 6 10| |
+------+------+
The program, in parentheses, can be read literally as "curtail link tail". This is the sort of program I'd expect from the title of your question.
Part of effective J programming is orienting the data (nouns) so that they are more readily manipulated by the programs (verbs).
Here is one way:
]a=: i. 3 4
0 1 2 3
4 5 6 7
8 9 10 11
3 ({."1 ; }."1) a
┌──────┬──┐
│0 1 2│ 3│
│4 5 6│ 7│
│8 9 10│11│
└──────┴──┘
In other words "take the first 3 items in each row of a and Link (;) with the result of dropping the first 3 items in each row of a"
Other methods and/or structures may be more appropriate depending on the exact use case.

J : Iverson's `table` function from _A Personal View of APL_

At the very end of A Personal View of APL (right before the references), Ken Iverson gave the following series of J code snippets:
[a=. b=. i. 5
0 1 2 3 4
a +/ b
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
over=.({.,.#;}.)&":#,
by=. (,~"_1 ' '&;&,.)~
a by b over a !/ b
+-+---------+
| |0 1 2 3 4|
+-+---------+
|1|1 1 1 1 1|
|2|0 1 2 3 4|
|3|0 0 1 3 6|
|4|0 0 0 1 4|
|5|0 0 0 0 1|
+-+---------+
table=. /([`by`]`over`)\
2 3 5 *table 1 2 3 4 5
+-+-------------+
| |1 2 3 4 5|
+-+-------------+
|2|2 4 6 8 10|
|3|3 6 9 12 15|
|4|5 10 15 20 25|
+-+-------------+
All of these work for me in J701, except the last, which gives me:
table=. /([`by`]`over`)\
2 3 5 *table 1 2 3 4 5
|rank error
| 2 3 5 *table 1 2 3 4 5
I notice in the original PDF from IBM that the quotes look more like:
table=. /([`by']`over')\
But this is a syntax error.
Was there a transcription error converting the PDF to HTML on the J site, or has the syntax of J changed?
I don't think that this is valid J syntax (I mean, for what it is supposed to do); maybe it was then, but not any more. The adverb table can be simply defined as:
table =: 1 :'[ by ] over u/'
The closest I can get to Iverson's version is:
table =: /([`by`]`over`)
but then you have to evoke (`:) the result of the adverb:
2 3 5 (*table`:6) 1 2 3 4 5
┌─┬─────────────┐
│ │1 2 3 4 5│
├─┼─────────────┤
│2│2 4 6 8 10│
│3│3 6 9 12 15│
│5│5 10 15 20 25│
└─┴─────────────┘
J has changed. Earlier versions allowed adverbs and conjunctions to be defined in ways that are no longer possible.
A version of table that is compatible with recent versions appears in the J Dictionary under "Bordering a Table"

Resources