Thanks! I appreciate the suggestions -- particularly using ravel instead of the double +/ +/ -- it felt clunky but ravel didn't jump to mind
My original version had more instances of /~ ... (%/~ * (~:/~ *. ( (0&=@|~))/~) ... I actually wanted to get rid of those hence using (..)"0/~ . I also prefer not to use "0 and think of it somewhat as a possible code smell. Not that it matters in this case, but I imagine table /~ as a loop(s) and it seemed more desirable to have fewer implicit loops (% * ~: *. 0&=@|~)"0/~ Would execute Loop through both arrays 1. Test for no residue on x/y -> return 1/0 2. Test for not equals on x/y AND with previous 3. Divide x/y, multiply by result of previous tests to effectively return 0 if those conditions don't hold Vs executing those operations each in their own loop on the larger array and combining the arrays Upon further thought, executing those as vector operations vs scalar operations may have desirable performance characteristics too... As with everything, it depends and the proof is in the timing! This example is small enough that it doesn't matter. I do think (% * ~: *. 0&=@|~)"0/~ is a little easier on the eyes (personally) than (%/~ * ~:/~ * 0 = |~/~), but not by a large margin. Also, I'm sure it depends on how the eyes & brain are trained. It's enjoyable to look and contemplate alternatives Anyhow, thanks again Joe On Sat, Dec 2, 2017 at 3:33 PM, Raul Miller <[email protected]> wrote: > If you don't mind some more suggestions: > > I would replace (+/)@:(+/)@: with +/@,@: (though in this case you > don't need @: at all and +/@,@ works fine). > > I would also use /~ thrice, yielding +/@,@(%/~ * ~:/~ * 0 = |~/~) > > Also, since you're going to be using +/ anyways, it's tempting to > remove the +/@ from that expression - but since you're using it on > each line, there is a good case for leaving it in place (cuts down on > intermediate storage space). > > I'm not sure if this is an actual improvement, but I try to avoid "0 > on expressions of primitives which have rank 0. > > Thanks, > > -- > Raul > > On Sat, Dec 2, 2017 at 3:20 PM, Joe Bogner <[email protected]> wrote: > > A slightly cleaner version of my day2b > > > > day2b =: (+/) @: (+/) @: ((% * ~: *. 0&=@|~)"0/~) > > > > +/ day2b"1 (". every LF cut input) > > > > > > > > thanks Raul & Henry for helping with the rank question on the other > thread > > > > On Sat, Dec 2, 2017 at 9:21 AM, Joe Bogner <[email protected]> wrote: > > > >> I only have a few minutes this morning but here is my unrefined > solutions > >> to partA and partB > >> > >> day2a =: +/ @: ([: (>./ - <./) @:". every LF cut ]) > >> > >> input =: 0 : 0 > >> 5 1 9 5 > >> 7 5 3 > >> 2 4 6 8 > >> ) > >> > >> day2a input > >> > >> > >> > >> day2b =: ([: +/ (+/ @: (%/~ * (~:/~ *. ( (0&=@|~))/~) ))) > >> > >> +/ day2b"1 (". every LF cut input) > >> > >> > >> > >> On Sat, Dec 2, 2017 at 6:12 AM, Raul Miller <[email protected]> > wrote: > >> > >>> What people like to do depends on the person. I tend to prefer compact > >>> expressions, but other people have different preferences (and some > >>> people prefer ([: f g) forms. > >>> > >>> Generally speaking, if f and g represent verbs, then ([: f g) is > >>> equivalent to f@:g and if g has infinite rank you can go f@g. > >>> However... if f and g represent verb *definitions* then for the > >>> general case you need (f)@:(g) -- you get a free parenthesis effect > >>> with every name, so if you are removing the name you might need the > >>> parenthesis that it provided. That said, if f was not a verb train > >>> then you can go f@:(g) and if g has infinite rank you can go f@(g). > >>> You can only eliminate the parenthesis from f@:(g) if it's g is a > >>> single word -- this gets back to whether f and g represent verbs or > >>> verb definitions ... or something else. > >>> > >>> That said, note that if f and g represent something other than verbs > >>> then ([: f g) might be an error, though there's a couple notable > >>> exceptions to that rule which involve certain conjunctions. To see > >>> this, note that @: is a conjunction. You can have f OR g be @: and the > >>> other one be a verb. The result will always generate errors when given > >>> a noun. However, if you instead use the : conjunction, surprisingly, > >>> there will be cases where the result can be evaluated (though one of > >>> the cases will not be the most compact form and will need another verb > >>> before the result is a verb. Also that form is something that you > >>> don't see used a lot (though it does have its uses - it's a "free > >>> parenthesis" case that doesn't get a lot of attention). > >>> > >>> Anyways... advent of code... > >>> > >>> +/@(>./ - <./) is how I originally expressed the day two problem. I'd > >>> ignore reading from a file, because I wouldn't use files here. > >>> > >>> That said, I went and tried it - I put the example data in a ".;._2]0 > >>> :0 definition like this: > >>> > >>> ss=:".;._2]0 :0 > >>> 5 1 9 5 > >>> 7 5 3 > >>> 2 4 6 8 > >>> ) > >>> > >>> This raises an issue - the rows are "ragged". There's two ways of > >>> dealing with this - one is you can put each row in a box, the other > >>> (which works in this case) is to remove the fill values from the rows > >>> before using them. I went with the latter approach and my solution > >>> became +/@:(>./"1 - (<./@-.&0)"1) > >>> > >>> For the second part, the sample data they gave was not ragged, and I > >>> didn't read ahead to notice that I'd be using the same dataset there > >>> (I skipped out on day 1). So my initial solution looked like this: > >>> > >>> require'stats' > >>> allpairs=: {~ 2 comb # > >>> cks=: [: +/((>./ % <./)@,@(#~ +./@(e. *./)"1)@allpairs)"1 > >>> > >>> Then changed it to allpairs=: ({~ 2 comb #)@-.&0"1 though on > >>> reflection that's not necessary. > >>> > >>> Not quite as compact as your approach, nor as efficient for the data > >>> we are working with here, but it works. > >>> > >>> Thanks, > >>> > >>> -- > >>> Raul > >>> > >>> > >>> On Sat, Dec 2, 2017 at 1:31 AM, Daniel Lyons <[email protected]> > >>> wrote: > >>> > 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 > >>> ---------------------------------------------------------------------- > >>> For information about J forums see http://www.jsoftware.com/forums.htm > >>> > >> > >> > > ---------------------------------------------------------------------- > > For information about J forums see http://www.jsoftware.com/forums.htm > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm > ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
