On the scale of my data, passing a match predicate to a **findIndices** function, and then retrieving matched values or keys by index, turns out to be enough.

Very fast in JS, and serviceable for my purposes in AS too.

```
on run
set xs to {"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu"}
-- A list of (string key, integer value) pairs:
-- kvs :: [(String, Int)]
set kvs to zip(xs, enumFromToInt(1, length of xs))
-- See longKey predicate below
findIndices(longKey, kvs) --> {5, 11, 17, 23}
script
on |λ|(kv)
"epsilon" = fst(kv)
end |λ|
end script
findIndices(result, kvs) --> {5, 7}
script matchedKey
on |λ|(i)
fst(item i of kvs)
end |λ|
end script
script matchedValue
on |λ|(i)
snd(item i of kvs)
end |λ|
end script
map(matchedKey, findIndices(longKey, kvs)) --> {"epsilon", "lambda", "epsilon", "lambda"}
map(matchedValue, findIndices(longKey, kvs)) --> {5, 11, 17, 23}
end run
-- Search predicate
-- longkey :: (k, v) -> Bool
on longKey(kv)
5 < length of fst(kv)
end longKey
-- findIndices :: (a -> Bool) -> [a] -> [Int]
on findIndices(p, xs)
script
property f : mReturn(p)'s |λ|
on |λ|(x, i)
if f(x) then
{i}
else
{}
end if
end |λ|
end script
concatMap(result, xs)
end findIndices
-- GENERIC FUNCTIONS ---------------------------------------------------------
-- https://github.com/RobTrew/prelude-applescript
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lng to length of xs
if 0 < lng and class of xs is string then
set acc to ""
else
set acc to {}
end if
tell mReturn(f)
repeat with i from 1 to lng
set acc to acc & |λ|(item i of xs, i, xs)
end repeat
end tell
return acc
end concatMap
-- enumFromToInt :: Int -> Int -> [Int]
on enumFromToInt(m, n)
if m ≤ n then
set lst to {}
repeat with i from m to n
set end of lst to i
end repeat
return lst
else
return {}
end if
end enumFromToInt
-- fst :: (a, b) -> a
on fst(tpl)
if class of tpl is record then
|1| of tpl
else
item 1 of tpl
end if
end fst
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- snd :: (a, b) -> b
on snd(tpl)
if class of tpl is record then
|2| of tpl
else
item 2 of tpl
end if
end snd
-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
{type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple
-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
set lng to min(length of xs, length of ys)
set lst to {}
repeat with i from 1 to lng
set end of lst to Tuple(item i of xs, item i of ys)
end repeat
return lst
end zip
```