I would like to construct a match spec to select the first element from a tuple when a match is found on the second element, or the second element when the first element matches. Rather than calling ets:match twice, can this be done in one match specification?
Yes.
In documentation there is example of is_integer(X), is_integer(Y), X + Y < 4711
, or [{is_integer, '$1'}, {is_integer, '$2'}, {'<', {'+', '$1', '$2'}, 4711}]
.
If you are using fun2ms
just write funciton with two clauses.
fun({X, Y}) when in_integer(X)
andalso X > 5 ->
Y;
({X, Y}) when is_integer(Y)
andalso Y > 5 ->
X.
But you could also create two MatchFunctions
. Each consist {MatchHead, [Guard], Return}
.
Match head basically tells you how your data looks (is it a tuple, how many elements ...) and assigns to each element match variable $N
where N
will be some number. Lets say are using two-element tuples, so your match head would be {'$1', '$2'}
.
Now lets create guards: For first function we will assume something simple, like first argument is integer greater than 10. So first guard will be {is_integer, '$2'}
, and second {'>', '$2', 5}
. In both we use firs element of our match head '$2'
. Second match function would have same guards, but with use of '$1'
.
And at last the return. Since we would like to just return one element, for first function it will be '$1'
, and for second '$2'
(returning tuple is little more complicated, since you would have to wrap it in additional on-element tuple).
So finally, when put together it gives us
[ _FirstMatchFunction = {_Head1 = {'$1', '$2'},
_Guard1 = [{is_integer, '$2},
{'>', '$2', 5}], % second element matches
_Return1 = [ '$1']}, % return first element
_SecondMatchFunction = {_Head2 = {'$1', '$2'},
_Guard2 = [{is_integer, '$1},
{'>', '$1', 5}], % second element matches
_Return2 = [ '$2']} ] % return first element
Havent had too much time to test it all, but it should work (maybe with minor tweaks).