Hacker News new | ask | show | jobs
by naniwaduni 333 days ago
Got a bit nerd-sniped here, but first of all we can reduce if A then B else . end === if A then B end since jq 1.7:

    jq 'walk(if type == "array" then (if length > 0 then [.[0]] end) end)'
Now we could contract those conditionals:

    jq 'walk(if type == "array" and length > 0 then [.[0]] end)'
but it turns out we can even more usefully express if length > 0 then [.[0]] end === [limit(1; .[])] == .[:1]:

    jq 'walk(if type == "array" then .[:1] end)'
From here, we can golf it a little further (this is kind of a generic type-matching pattern):

    jq 'walk(arrays[:1] // .)'
although this does incur a bit more overhead than checking type directly.

Speaking of overhead, though, it turns out that the implementation of walk/1 (https://github.com/jqlang/jq/blob/master/src/builtin.jq#L212) will actually run the filter on every element of an array, even though we're about to throw most of them out, which we can eliminate by writing the recursion explicitly:

    jq 'def w: if type=="array" then [limit(1; .[]|w)] elif type=="object" then .[] |= w end; w'
which gets the operation down from ~200 ms on my machine (not long enough to really get distracted, but enough to feel the wait) to a perceptually instant ~40 ms (which is mostly just the cost of reading the input). Now we can golf it down a little more:

    jq 'def w: if type=="array" then [limit(1; .[]|w)] else objects[] |= w end; w'
    jq 'def w: (arrays[:1]|map(w)) // (objects[] |= w); w'
(the precedence here actually allows us to eliminate the parens here...)

    jq 'def w: arrays |= .[:1]|iterables[] |= w; w'
And, inaccessibility of the syntax aside, I think this does an incredible job of expressing the essence of what we're trying to do: we trim any array down to its first element, and then recursively apply the same transformation throughout the structure. jq is a very expressive language, it just looks like line noise...
1 comments

Hat off.-

PS. Also, if I may l, thanks for the walkthrough - I'd be clapping with just the short form at the end, but the reasoning is appreciated.-