RosettaCodeData/Task/Calendar/Mathematica/calendar-1.math

50 lines
3.6 KiB
Plaintext

DataGrid[
rowHeights:{__Integer},
colWidths:{__Integer},
spacings:{_Integer,_Integer},
borderWidths:{{_Integer,_Integer},{_Integer,_Integer}},
options_Association,
data:{__List?MatrixQ}]:=
With[
(*Need to make sure we have sensible defaults for the decoration options.*)
{alignment=Lookup[options,"alignment",{0,0}],
background=Lookup[options,"background"," "],
dividers=Lookup[options,"dividers",{" "," "," "}],
border=Lookup[options,"border"," "],
dims={Length[rowHeights],Length[colWidths]}},
(*Pad the data so that it will fit into the specified rectangle (list of lists).*)
With[{augmentedData=PadRight[data,Times@@dims,{{{background}}}]},
(*Create a matrix of dimensions based on desired rectangle. Once we have a matrix of cells we can "thread" these two matrices and use that data to coerce each cell into its final dimensions.*)
With[{cellDims=ArrayReshape[Outer[List,rowHeights,colWidths],{Times@@dims,2}]},
(*MatrixAlign, defined below, rescales and aligns each cell's data.*)
With[{undecoratedGrid=Partition[MapThread[MatrixAlign[alignment,#1,background][#2]&, {cellDims,augmentedData}],dims[[2]]]},
(*Add the spacing to each row.*)
With[{dividedRows=MapThread[Transpose[Riffle[#2,{ConstantArray[dividers[[2]],{#1,spacings[[2]]}]},{2,-2,2}]]&, {rowHeights,undecoratedGrid}]},
(*Add the spacing between rows.*)
With[{dividedColumn=Riffle[dividedRows,{Transpose[Riffle[ConstantArray[dividers[[1]],{spacings[[1]],#}]&/@colWidths,{ConstantArray[dividers[[3]],spacings]},{2,-2,2}]]},{2,-2,2}]},
(*Assemble all cell rows into actual character rows. We now have one large matrix.*)
With[{dividedGrid=Catenate[Map[Flatten,dividedColumn,{2}]]},
(*Add borders.*)
ArrayPad[dividedGrid,borderWidths,border]]]]]]]];
DataGrid[dims:{_Integer,_Integer},spacings_,borderWidths_,options_,data:{__List?MatrixQ}]:=
(*Calculate the max height for each row and max width for each column, and then just call the previous DataGrid function above.*)
With[
{rowHeights=Flatten@BlockMap[Max[Part[#,All,All,1]]&,ArrayReshape[Dimensions/@data,Append[dims,2],1],{1,dims[[2]]}],
colWidths=Flatten@BlockMap[Max[Part[#,All,All,2]]&,ArrayReshape[Dimensions/@data,Append[dims,2],1],{dims[[1]],1}]},
DataGrid[rowHeights,colWidths,spacings,borderWidths,options,data]];
(*This could probably be simplified, but I like having all of the aligment options explicit and separate for testability.*)
MatrixAlign[{-1,-1},dims_,pad_]:=PadRight[#,dims,pad]&;
MatrixAlign[{-1,0},dims_,pad_]:=PadRight[CenterArray[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{-1,1},dims_,pad_]:=PadRight[PadLeft[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{0,-1},dims_,pad_]:=CenterArray[PadRight[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{0,0},dims_,pad_]:=CenterArray[#,dims,pad]&;
MatrixAlign[{0,1},dims_,pad_]:=CenterArray[PadLeft[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,-1},dims_,pad_]:=PadLeft[PadRight[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,0},dims_,pad_]:=PadLeft[CenterArray[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,1},dims_,pad_]:=PadLeft[#,dims,pad]&;
(*While the grid functions make no assumptions about the format of the data, we will be using them with string/character data, and we will eventually want to output a calendar as a single large string. AsString gives us a standard method for transforming a matrix of characters into a string with rows delimited by newlines.*)
AsString[matrix_List?MatrixQ]:=StringRiffle[matrix,"\n",""];