I really enjoy using chains of map.filter.foreach.map in scala, it feels powerful but also simple
I imagine piping in bash feels similar, so there's at least a common problem/solution between them
I imagine piping in bash feels similar, so there's at least a common problem/solution between them
It is. Piping is akin to an untyped subset of working with Scala's collections, and there's a similar workflow between the two, e.g.:
In bash, you build up a command line with something like (as a stupid example, the number of unique file sizes in a directory):
Step 1) $ ls -l
Step 2) $ ls -l | awk '{print $5}'
Step 3) $ ls -l | awk '/\d+/ {print $5}'
Step 4) $ ls -l | awk '/\d+/ {print $5}' | sort -n
Step 5) $ ls -l | awk '/\d+/ {print $5}' | sort -n | uniq
You can see the correspondence with collections--typically building up in the editor in a similar staged manner ending with something like: Process("ls -l").lines // ls -l part
.map(_.split("\\s+")) // awk part {
.filter(_.length > 4) // ...
.map(_.apply(4).toInt) // }
.sorted // sort -n part
.distinct // uniq part
The tradeoffs between the two are essentially verbosity versus data safety (perhaps not important with a throwaway inspection, but more important when working on larger programs...).However, the building process is the same--you don't write the latter all at once, you gradually mold the pipeline until you get the output you want.
[1] pry(main)> `ls`
=> "README.md\n" + "_build\n" + "config\n" + "lib\n" + "mix.exs\n" + "test\n"
[2] pry(main)> `ls`.split
=> ["README.md", "_build", "config", "lib", "mix.exs", "test"]
[3] pry(main)> `ls`.split.map(&:upcase)
=> ["README.MD", "_BUILD", "CONFIG", "LIB", "MIX.EXS", "TEST"]
[4] pry(main)> `ls`.split.map(&:upcase).select { |x| x.match(/E/) }
=> ["README.MD", "MIX.EXS", "TEST"]