1
\$\begingroup\$

I have a fixed-width input format. The widths are known to me. Suppose I am told that the first field is 20 characters, the second is 10, the third is 12. The total width of a row should therefore be 42 characters. I have a working solution:

parseFW =: dyad def '(+/ (0,+/\x) ="(0 1) i. (+/x)) <;.1 y'"(_ _1)

My plan here is to use the dyadic form of cut (i.e. ;.) with a boolean array to indicate the fret locations. I'm going to get the rolling sum of the field widths to find where the indices of the frets and then I'm going to reduce that to a boolean array by looking for those indices.

This works:

   input =. noun define
NAME                STATE     TELEPHONE  
John Smith          WA        418-Y11-4111
Mary Hartford       CA        319-Z19-4341
Evan Nolan          IL        219-532-c301
)

   $ input
171

  (20 10 12) parseFW >cutLF input
┌────────────────────┬──────────┬────────────┐
│NAME                │STATE     │TELEPHONE   │
├────────────────────┼──────────┼────────────┤
│John Smith          │WA        │418-Y11-4111│
├────────────────────┼──────────┼────────────┤
│Mary Hartford       │CA        │319-Z19-4341│
├────────────────────┼──────────┼────────────┤
│Evan Nolan          │IL        │219-532-c301│
└────────────────────┴──────────┴────────────┘

      $ (20 10 12) parseFW >cutLF input
4 3

My concerns are:

  • In my head, I feel like this shouldn't take so much code to accomplish and I'm missing something
  • Is it idiomatic? I'm new to J and would like to know
  • I. :^ _1 looks like it would do the work I need to convert the rolling sum to a boolean array of fret locations, but it doesn't seem to work (domain error). Am I misusing it?
  • Efficiency isn't a huge concern of mine, but I would like to know if I'm missing a "special code" opportunity here with this approach
\$\endgroup\$
1
\$\begingroup\$

For reference, in case anyone stumbles across this page later, and as discussed in your thread here.

Something like this would do the trick:

parseFW=: (i.@{:@$@] e. 0,+/\@[) <;.1"1 ]

(Though when I test against your input, I'm tripped up by a leading space on each line of your 'input' value, which does not match the specific width values you have used here. Need to also deal with that issue somehow. I would recommend either manually removing those spaces, or dropping the first character on each row before handing off to either implementation of parseFW).

That said, to get an exact workalike to your parseFW (throws an error because the record size is wrong, rather than slicing at the "wrong" column positions on the larger records), you could do this:

parseFW=: (i.@(+/) e. 0,+/\)@[ <;.1"1 ]
\$\endgroup\$
  • \$\begingroup\$ There were some issues copying from Emacs into the question; I've tried to address them. \$\endgroup\$ – Daniel Lyons Nov 20 '17 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.