diff --git a/doc/Expr.adoc b/doc/Expr.adoc index 5567ef2..bbfd53f 100644 --- a/doc/Expr.adoc +++ b/doc/Expr.adoc @@ -1875,13 +1875,21 @@ TIP: Iterators built on custom data-sources can provide additional named operato There are also some infixed operators that can be used with iterators. They are defined as follows. * <<_cat,cat operator>> -* <<_diget,digest operator>> +* <<_digest,digest operator>> * <<_filter,filter operator>> * <<_groupby,groupby operator>> * <<_map,map operator>> //* <<_reduce,reduce operator>>: applies a binary expression cumulatively to the elements of the iterator, from left to right, to reduce the iterator to a single value. //* <<_zip,zip operator>>: takes two or more iterators and returns a list of tuples, where the i-th tuple contains the i-th element from each of the input iterators. + +==== Automatic variables in operators +At each iteration, the following automatic variables are available for use in the expression of the [blue]`digest`, [blue]`filter`, [blue]`groupby`, and [blue]`map` operators. + +* `$_`: the current element of the iterator. +* `$__`: the index of the current element in the iterator, starting from 0. +* `$_#`: the number of elements already visited in the iterator, starting from 0. + --- ==== [blue]`cat` operator diff --git a/operator-digest.go b/operator-digest.go index 78f2540..64a8230 100644 --- a/operator-digest.go +++ b/operator-digest.go @@ -45,7 +45,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { for item, err = it.Next(); err == nil; item, err = it.Next() { ctx.SetVar("_", item) ctx.SetVar("__", it.Index()) - ctx.SetVar("_#", it.Count()) + ctx.SetVar("#", it.Count()) if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil { if rightValue == nil { break @@ -53,7 +53,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { lastValue = rightValue } } - ctx.DeleteVar("_#") + ctx.DeleteVar("#") ctx.DeleteVar("__") ctx.DeleteVar("_") if err != nil { diff --git a/operator-filter.go b/operator-filter.go index a9a6797..f8ee9a7 100644 --- a/operator-filter.go +++ b/operator-filter.go @@ -110,9 +110,9 @@ func (it *filterIterator) Next() (item any, err error) { for attempt, err = it.itSrc.Next(); err == nil; attempt, err = it.itSrc.Next() { ctx.SetVar("_", attempt) ctx.SetVar("__", it.Index()) - ctx.SetVar("_#", it.Count()) + ctx.SetVar("#", it.Count()) result, err = it.expr.Compute(ctx) - ctx.DeleteVar("_#") + ctx.DeleteVar("#") ctx.DeleteVar("__") ctx.DeleteVar("_") diff --git a/operator-groupby.go b/operator-groupby.go index 70535a4..9130e95 100644 --- a/operator-groupby.go +++ b/operator-groupby.go @@ -62,7 +62,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { for item, err = it.Next(); err == nil; item, err = it.Next() { ctx.SetVar("_", item) ctx.SetVar("__", it.Index()) - ctx.SetVar("_#", it.Count()) + ctx.SetVar("#", it.Count()) var sItemKey string @@ -71,7 +71,11 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { sItemKey = strconv.Itoa(int(it.Index())) } else if d.HasKey(sKey) { if keyValue, exists := d.GetItem(sKey); exists { - sItemKey = fmt.Sprintf("%v", keyValue) + if s, ok := keyValue.(string); ok { + sItemKey = s + } else { + sItemKey = fmt.Sprintf("%v", keyValue) + } } else { sItemKey = "_" } @@ -92,7 +96,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { ls.AppendItem(item) values.SetItem(sItemKey, ls) - ctx.DeleteVar("_#") + ctx.DeleteVar("#") ctx.DeleteVar("__") ctx.DeleteVar("_") }