Thanks to everyone for sharing solutions yesterday and especially to those with
advice for me, I really appreciate it!
Today's problem has to do with computing checksums. Like yesterday, the first
part and the second part bear some kind of family resemblance that you can
probably leverage; my first solution doesn't really help with my second, but oh
well.
Part one is basically to examine a matrix comparing items row-by-row, finding
the differences between the largest and smallest elements of each, and then
summing those differences. My solution:
a =. ".&.>cutLF fread '~/Desktop/input'
checksum =. monad def '+/> (>./ - <./) &.> y'
There's a fair amount of boxing and unboxing going on here. The actual input
file is a rectangular matrix, but the example input in the problem is not, so I
assumed the input wasn't either. This could certainly be simplified. The tacit
version is also not too bad:
[: +/ [: > (>./ - <./)&.>
As a beginner I am kind of suspicious of tacits with a lot of cap. It looks to
me like humans usually generate tacits with @: or @ instead, and while it seems
to me that "[: f g" ought to transform into "f @: g" 100% of the time, it
doesn't seem to be quite right when I try it.
For part two, the conditions change to finding two values such that one divides
the other and then taking the result of that division for each row, summing up
the result of the divisions.
My first thought was to form the cross product of the divisors, but you get
spurious results along the diagonal arising from checking values against
themselves. So then I was building the identity matrix to mask that out and
then using the (shape shape) #: , I. trick to convert the result back into
coordinates, so I could use { to obtain the values, so I could then … and it
just felt a bit like a Rube Goldberg device, so I did some chores.
When I came back I had realized that I could avoid a great deal of that work by
just multiplying the division result by my conditions (x and y not being equal,
x and y being divisors) and then discard the zeros, so I came up with this:
checksum2 =. monad def '+/ 0 -.~ ,y ((0=|) *. ~: *. (% >. %~))"(0 1) y'
The tacit (% >. %~) is standing in for "do the division whichever way works".
So you can see the conditions inside that largeish tacit. I could probably put
a reflex operator on there and not pass y in again on the x side, I'm realizing
right now. 0 -.~ is discarding the zeros and then I sum up the difference.
Unlike the first, this one is expecting a rectangular matrix rather than a list
of boxes, and I obviously profited from that decision and should go back and
revisit my first solution.
It still feels a bit like more code than there is work to do, but I'm pleased
that I got to the solution.
Tacit version of checksum2 is
13 : '+/ 0 -.~ ,y ((0=|) *. ~: *. (% >. %~))"(0 1) y'
[: +/ 0 -.~ [: , ((0 = |) *. ~: *. % >. %~)"0 1~
Ah, see it threw a reflex on the end.
Very fun! Thanks for reading,
--
Daniel Lyons
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm