Dear Statalisters,

Thanks to Kit Baum, a new command frapply is now available in SSC.

Beginning with version 16, Stata can hold multiple data frames in memory. This changed how I work in Stata as I fully integrated frames into my workflow. However, using the stock frames commands felt somewhat tedious as I had to write multiple lines of command to do simple things like putting a summary of a subset into a new frame.

frapply simplifies this process. It arose from my need to write one-liners to iteratively extract what I want from the current dataset I am working with and look at the result without changing it. It applies a command or a series of commands to the dataset in the specified (or current) frame and optionally puts the result into another frame. Otherwise destructive commands (such as drop, keep, collapse, contract, etc.) can be daisy-chained somewhat similar to the pipe operator in R (and in Tidyverse), all the while preserving the dataset. This can be useful in interactive and experimental settings where we want to quickly and iteratively summarize and/or transform the dataset without changing it. It can also be a convenient drop-in replacement for the frames prefix and a substitute for frames commands such as frame copy and frame put. It can do what those commands can do--but is more flexible.

As an elementary example, let's say we want to load up the auto data, subset expensive cars, and put averages by trunk space into a different frame. And we want to try different thresholds for what "expensive" would entail, so we will repeatedly run this chunk of code.
Code:
frame change default
capture frame drop temp
frame put if price > 10000, into(temp)
frame change temp
collapse price, by(trunk)
list

Using frapply, this can be written more concisely as follows.
Code:
frapply default if price > 10000, into(temp, replace change): collapse price, by(trunk) || list
frapply takes the input frame, subsets it, applies daisy-chained commands, and puts the result in either a new or an existing frame (or even a temporary frame if into() option is omitted). We could rerun this line and get the same result regardless of the current frame.

I hope this command improves your workflow. Comments and suggestions are always welcome. Also, feel free to let me know if you find any errors.