Skip to content

Instantly share code, notes, and snippets.

@kubukoz
Last active March 9, 2018 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubukoz/d554573e74c97bc2c6c1bb6987c283d1 to your computer and use it in GitHub Desktop.
Save kubukoz/d554573e74c97bc2c6c1bb6987c283d1 to your computer and use it in GitHub Desktop.
Transpose a List of HLists.
//see original SO answer: https://stackoverflow.com/a/49184270/1927425
import shapeless.ops.hlist._
import shapeless.{::, _}
trait EmptyOf[T <: HList, AsList <: HList] {
def empty(): AsList
}
object EmptyOf {
implicit val emptyOfHNil: EmptyOf[HNil, HNil] = () => HNil
implicit def emptyOfList[H, T <: HList, TEmpty <: HList](
implicit ev: EmptyOf[T, TEmpty]): EmptyOf[H :: T, List[H] :: TEmpty] =
() => List.empty[H] :: ev.empty()
}
object Sample {
object concat extends Poly2 {
implicit def prepend[S] = at[List[S], S]((list, s) => s :: list)
}
def transpose[T <: HList, U <: HList](lists: List[T])(implicit
emptyOf: EmptyOf[T, U],
zip: ZipWith.Aux[U, T, concat.type, U]): U =
lists.foldLeft(emptyOf.empty())(_.zipWith(_)(concat))
def main(args: Array[String]): Unit = {
val myList: List[Int :: String :: Boolean :: HNil] = List(
1 :: "sample" :: true :: HNil,
2 :: "sample2" :: false :: HNil,
3 :: "sample3" :: true :: HNil
)
val actual: List[Int] :: List[String] :: List[Boolean] :: HNil = transpose(myList)
val expected: List[Int] :: List[String] :: List[Boolean] :: HNil =
List(3, 2, 1) ::
List("sample3", "sample2", "sample") ::
List(true, false, true) ::
HNil
println(actual == expected)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment