01mf02 / jaq

A jq clone focussed on correctness, speed, and simplicity
MIT License
2.7k stars 67 forks source link

Support JQ's index/rindex function #154

Closed John-Toohey closed 6 months ago

John-Toohey commented 8 months ago

Jq has the index and rindex functions which don't seem to be supported in jaq. Is there a specific reason for this? Thank you for your time.

kklingenberg commented 8 months ago

I don't think it's intentional. I'd even guess that anything from jq that's purposely excluded from jaq is documented in the README. For these filters (indices, index, rindex) you could just implement them in std. This is my attempt at it, using two auxiliary filters to deal with iterating over strings, and windowing:

# Indexing
def indices($i):
  def enumerate:
    . as $thing |
    if type == "string"
    then range(length) | [., $thing[.:.+1]]
    else range(length) | [., $thing[.]]
    end;

  def windowed($size):
    if $size <= 0 then empty
    else . as $array | range(length - $size + 1) | $array[.:. + $size]
    end;

  if ["string", "array"] | any(. == ($i | type))
  then [[windowed($i | length)] | enumerate | select(.[1] == $i)[0]]
  else [enumerate | select(.[1] == $i)[0]]
  end;

def index($i):  indices($i) | .[0];
def rindex($i): indices($i) | .[-1:][0];

It's not very good, and fails on ["a", "b", "c"] | indices("b") (mostly because of incomplete type dispatching), but it could be a start.

kklingenberg commented 8 months ago

I fixed the error by changing the condition to if ($i | type) == "array" or (type == "string" and ($i | type) == "string"), based on jq's implementation. Then I realized that jq gives special meaning to array as indices as in [1,2][[1,2]]. jaq doesn't allow that :thinking:. That is probably intentionally not supported :sweat_smile:

Anyway I put my implementation of these filters in a PR, with tests copied straight from jq's website: #158