I had also thought of a solution that made use of the join functions, although not as elegantly as yours.
In fact, what I was looking for was an alternative route that was competitive in speed of execution.
To tell the truth, I didn’t even know the existence of the semijoin function.
If I have not misunderstood this take, in the case of many correspondences only one (the first?).
But is that what @xinchin is asking?
Perhaps an example a little richer than the one provided would be useful, with the expected result in the case of many occurrences if this is a case existing within the same branch (and how they would be distinguished in that case)
df = DataFrame(
branch = [1,1,2,1,1,2,2],
from = [1,2,3,4,5,1,6],
to = [4,7,1,1,2,3,9]
[SplitApplyCombine.innerjoin(l->(l.branch,l.from,l.to),r->(r.branch,r.to,r.from),(l,r)->(l.branch,l.from,l.to),eachrow(g),eachrow(g)) for g in grp]