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