diff --git a/shared/src/main/scala/ListHelpers.scala b/shared/src/main/scala/ListHelpers.scala index d30f385f5..61deccecc 100644 --- a/shared/src/main/scala/ListHelpers.scala +++ b/shared/src/main/scala/ListHelpers.scala @@ -40,7 +40,6 @@ object ListHelpers: end filter /** A wrapper call to the generator method in interpreter */ - def generate(function: VFun, initial: VList)(using ctx: Context): VList = val firstN = initial.length match case 0 => ctx.settings.defaultValue @@ -245,40 +244,43 @@ object ListHelpers: parts.toSeq end split + /** Transpose a matrix. + * + * Hangs on infinite lists of finite lists. See [[transposeSafe]] for a version that handles those. + * Based on [[https://github.com/Adriandmen/05AB1E/blob/master/lib/commands/matrix_commands.ex 05AB1E's implementation]]. + */ def transpose(iterable: VList, filler: Option[VAny] = None)(using ctx: Context ): VList = - /*Transposes a matrix - In order to handle infinite lists, it generates the transpose - antidiagonal by antidiagonal. - */ - val matrix = iterable.map(makeIterable(_)) - def genRow(r: BigInt) = - val temp: LazyList[Option[VAny]] = LazyList - .unfold(0) { c => - if !matrix.isDefinedAt(c) then None - else if matrix(c).isDefinedAt(r) then - Some((Some(matrix(c).index(r)), c + 1)) - else if filler.isDefined then - Some((Some(filler.getOrElse(VNum(0))), c + 1)) - else Some((None, c + 1)) + val out = filler match + case None => LazyList.unfold(matrix) { matrix => + val remaining = matrix.filter(_.nonEmpty) + Option.when(remaining.nonEmpty) { + (remaining.map(_.head), remaining.map(_.tail)) + } + } + case Some(filler) => LazyList.unfold(matrix) { matrix => + Option.when(matrix.exists(_.nonEmpty)) { + (matrix.flatMap(_.headOption.getOrElse(filler)), matrix.map(_.tail)) + } } - VList.from(temp.flatten) - - val out: LazyList[VAny] = LazyList - .unfold(0) { r => - if !matrix.exists(_.isDefinedAt(r)) then None - else - val row = genRow(r) - if row.forall(_.isInstanceOf[String]) then Some((row.mkString, r + 1)) - else Some((row, r + 1)) - } VList.from(out) - end transpose + /** Transpose a matrix. Uses the length of the first row of the inputted matrix + * as the number of columns in the resulting matrix. + * + * @see transpose + */ + def transposeSafe(iterable: VList, filler: Option[VAny] = None)(using + ctx: Context + ): VList = + val matrix = iterable.map(makeIterable(_)) + ??? + end transposeSafe + def vectorisedMaximum(iterable: VList, b: VVal): VList = VList.from(iterable.map { a => (a: @unchecked) match