Search code examples
scalagroup-bynestedscalazshapeless

FP or typelevel tools to groupBy on deep leaf in nested data?


I got a deeply nested datastructure:

Seq[Seq[(String, Seq[(String, Seq[(String, Try[Boolean])])], Long)]]

Is there a nice functional way to groupBy on Try.isFailure?

With Shapeless it is possible to search in arbitrary nested datastructures, as can be seen here. But finding is only one part of my problem. I saw zippers and lenses, they are nice but afaik they are not the right tool here.

For info, the data represents results of some test code. The layers are: permutations of configurations => tested component => mutation on data => testing code. Strings are descriptions, long is the time it took to finish for each component test. I want to create two lists, one with all failures keeping all the info where and when they happened keeping exceptions as info, and one corresponding one for successes.

Is there a solution out there already?

Note: the most sensible approach for that particular case would be to redesign my testcode such that two lists, one failurelist and one successlist are created from the start. But still, I'd like to know. This kind of problem doesn't seem to be uncommon.


Solution

  • It may not be the most creative solution, but you could partition the outermost Seq as follows:

    val partitioned = seq.partition{ s =>
      val flat = s.map(_._2).flatten.map(_._2).flatten
      flat.find(tup => tup._2.isFailure).isDefined
    }
    

    In this example, the first line in the partition body flattens out the nested structure so you are left with the inner most Seq. Then, from there, the predicate condition to return for the partition call is derived from seeing if the inner most Seq contains at least one Failure. What you are left with is a tuple where the first Seq is the outermost items that have `failures in their nested structures and the second one is ones where no failures occurred.

    This is probably not the best performing solution, but it's succinct as far as code lines is concerned. In fact, you could even do it in one line as follows:

    val partitioned = seq.partition(_.map(_._2).flatten.map(_._2).flatten.find(_._2.isFailure).isDefined)