Automating table creation

This creates the same table as yours. The \TypesetTable command has also an optional argument for setting the threshold on the number of columns, see the example.

\documentclass{article}
\usepackage[a4paper,margin=1cm]{geometry}
\usepackage{xparse,booktabs}

\ExplSyntaxOn
\NewDocumentCommand{\TypesetTable}{ O{10} m }
 {
  \nebu_typeset_table:nn { #1 } { #2 }
 }

\keys_define:nn { nebutable }
 {
  Del1 .tl_set:N = \l__nebu_deli_tl,
  PDel1 .tl_set:N = \l__nebu_pdeli_tl,
  Del2 .tl_set:N = \l__nebu_delii_tl,
  PDel2 .tl_set:N = \l__nebu_pdelii_tl,
 }

\int_new:N \l__nebu_columns_int
\int_new:N \l__nebu_pdeli_total_int
\int_new:N \l__nebu_pdelii_total_int
\int_new:N \l_nebu_countrows_int
\seq_new:N \l__nebu_deli_seq
\seq_new:N \l__nebu_pdeli_seq
\seq_new:N \l__nebu_delii_seq
\seq_new:N \l__nebu_pdelii_seq
\tl_new:N \l__nebu_preamble_tl
\tl_new:N \l__nebu_table_body_tl

\cs_new_protected:Npn \nebu_typeset_table:nn #1 #2
 {
  \keys_set:nn { nebutable } { #2 }
  \seq_set_split:NnV \l__nebu_deli_seq { , } \l__nebu_deli_tl
  \seq_set_split:NnV \l__nebu_pdeli_seq { , } \l__nebu_pdeli_tl
  \seq_set_split:NnV \l__nebu_delii_seq { , } \l__nebu_delii_tl
  \seq_set_split:NnV \l__nebu_pdelii_seq { , } \l__nebu_pdelii_tl
  % Compute the number of inner columns
  \int_set:Nn \l__nebu_columns_int
   {
    \int_min:nn { #1 }
     {
      \int_max:nn { \seq_count:N \l__nebu_deli_seq }
                  { \seq_count:N \l__nebu_delii_seq }
     }
   }
  % Define the table preamble
  \tl_set:Nx \l__nebu_preamble_tl
   { l c *{ \int_to_arabic:n { \l__nebu_columns_int } } { c } c }
  % Compute the total for Del1
  \int_zero:N \l__nebu_pdeli_total_int
  \seq_map_inline:Nn \l__nebu_pdeli_seq
   { \int_set:Nn \l__nebu_pdeli_total_int { \l__nebu_pdeli_total_int + ##1 } }
  % Compute the total for Del2
  \int_zero:N \l__nebu_pdelii_total_int
  \seq_map_inline:Nn \l__nebu_pdelii_seq
   { \int_set:Nn \l__nebu_pdelii_total_int { \l__nebu_pdelii_total_int + ##1 } }
  % Start building the table contents
  \tl_clear:N \l__nebu_table_body_tl
  \tl_put_right:Nx \l__nebu_table_body_tl
   { \exp_not:N \multicolumn { \int_to_arabic:n { \l__nebu_columns_int + 2 } } { c } { } }
  \tl_put_right:Nn \l__nebu_table_body_tl { & Sum \\ \midrule }

  % Insert Del1
  \__nebu_insert_table_part:nn { deli } { Del~1 }
  \tl_put_right:Nn \l__nebu_table_body_tl { \midrule }
  % Insert Del2
  \__nebu_insert_table_part:nn { delii } { Del~2 }

  % Add total
  \tl_put_right:Nx \l__nebu_table_body_tl
   {
    \exp_not:N \midrule
    \exp_not:N \multicolumn
                { \int_to_arabic:n { 2 + \l__nebu_columns_int } }
                { r }
                { Total~antall~poeng }
    &
    \int_to_arabic:n { \l__nebu_pdeli_total_int + \l__nebu_pdelii_total_int }
    \exp_not:N \\
   }

  % Print the table
  \use:x{ \exp_not:N \begin{tabular}{\l__nebu_preamble_tl} }
  \toprule
  \l__nebu_table_body_tl
  \bottomrule
  \end{tabular}
}

\cs_new_protected:Npn \__nebu_insert_table_part:nn #1 #2
 {
  \int_set:Nn \l_nebu_countrows_int
   {
    \seq_count:c { l__nebu_#1_seq } / \l__nebu_columns_int
   }
  \int_step_inline:nnnn { 1 } { 1 } { \l_nebu_countrows_int }
   {
    % First line
    \int_compare:nTF { ##1 = 1 }
     {
      \tl_put_right:Nn \l__nebu_table_body_tl { #2 & Oppgave & }
     }
     {
      \tl_put_right:Nx \l__nebu_table_body_tl
       { \exp_not:N \cmidrule{3-\int_to_arabic:n { \l__nebu_columns_int + 3 }} }
      \tl_put_right:Nn \l__nebu_table_body_tl { & & }
     }
    \int_step_inline:nnnn 
     { (##1 - 1)*\l__nebu_columns_int + 1 } 
     { 1 }
     { ##1 * \l__nebu_columns_int }
     {
      \tl_put_right:Nx \l__nebu_table_body_tl 
       { \seq_item:cn { l__nebu_#1_seq } { ####1 } & }
     }
     \tl_put_right:Nn \l__nebu_table_body_tl { \\ }
     % Second line
    \int_compare:nTF { ##1 = 1 }
     { \tl_put_right:Nn \l__nebu_table_body_tl { & Poeng & } }
     { \tl_put_right:Nn \l__nebu_table_body_tl { & & } }
     \int_step_inline:nnnn 
      { (##1 - 1)*\l__nebu_columns_int + 1 }
      { 1 }
      { ##1 * \l__nebu_columns_int }
      {
       \tl_put_right:Nx \l__nebu_table_body_tl
        { \seq_item:cn { l__nebu_p#1_seq } { ####1 } & }
      }
      \tl_put_right:Nx \l__nebu_table_body_tl
       {
        \int_compare:nT { ##1 = 1 }
         { \int_to_arabic:n { \use:c { l__nebu_p#1_total_int } } }
        \exp_not:N \\
       }
   }
 }

\ExplSyntaxOff

\setlength{\parindent}{0pt} % just for the example

\begin{document}

\TypesetTable{
  Del1= {1a1,1a2,1a3,1b1,1b2,1b3,1c,1d1,1d2,1d3,1e1,1e2,1f,1g1,1g2,1g3},
  PDel1={1,  1,  1,  1,  2,  2,  2, 2,  0,  2,  2,  2,  2, 2,  2,  0},
  Del2= {2a,2b,2c,2d,2e,2f,3a1,3a2,3b,4a,4b,4c,4d,5a,5b,5c,6a,6b},
  PDel2={2, 2, 2, 2, 2, 2, 2,  2,  3, 2, 2, 2, 2, 1, 2, 2, 2, 2}
}

\bigskip

\TypesetTable[8]{
  Del1= {1a1,1a2,1a3,1b1,1b2,1b3,1c,1d1,1d2,1d3,1e1,1e2,1f,1g1,1g2,1g3},
  PDel1={1,  1,  1,  1,  2,  2,  2, 2,  0,  2,  2,  2,  2, 2,  2,  0},
  Del2= {2a,2b,2c,2d,2e,2f,3a1,3a2,3b,4a,4b,4c,4d,5a,5b,5c,6a,6b},
  PDel2={2, 2, 2, 2, 2, 2, 2,  2,  3, 2, 2, 2, 2, 1, 2, 2, 2, 2}
}


\end{document}

enter image description here


This is a new implementation that allows to gather the exercises label and grades during the document and print the table anywhere; it requires two runs before stabilizing, as it uses the .aux file.

The \addtoDel macro receives three arguments; the first is 1 or 2, for the two kinds, the second is the label and the third is the grade. You'll probably be using it in the macro for typesetting the exercises.

The new \TypesetTable command has only one optional argument to set the threshold number of inner columns.

\documentclass{article}
\usepackage[a4paper,margin=1cm]{geometry}
\usepackage{xparse,booktabs}

\ExplSyntaxOn

\NewDocumentCommand{\TypesetTable} { O{10} }
 {
  \seq_if_empty:NT \g__nebu_deli_seq
   {
    \seq_gput_right:Nn \g__nebu_deli_seq { X }
    \seq_gput_right:Nn \g__nebu_pdeli_seq { 0 }
    \seq_gput_right:Nn \g__nebu_delii_seq { X }
    \seq_gput_right:Nn \g__nebu_pdelii_seq { 0 }
   }
  \nebu_typeset_table:n { #1 }
 }

\NewDocumentCommand{\addtoDel}{mmm}
 {
  \clist_gput_right:cn { g__nebu_del\int_to_roman:n { #1 }_clist } { #2 }
  \clist_gput_right:cn { g__nebu_pdel\int_to_roman:n { #1 }_clist } { #3 }
 }

\AtEndDocument{
  \iow_shipout:cx { @auxout }
   { \exp_not:N \LoadDel { i } { \g__nebu_deli_clist } }
  \iow_shipout:cx { @auxout }
   { \exp_not:N \LoadPDel { i } { \g__nebu_pdeli_clist } }
  \iow_shipout:cx { @auxout }
   { \exp_not:N \LoadDel { ii } { \g__nebu_delii_clist } }
  \iow_shipout:cx { @auxout }
   { \exp_not:N \LoadPDel { ii } { \g__nebu_pdelii_clist } }
}
\cs_generate_variant:Nn \iow_shipout:Nx { c }
\NewDocumentCommand{\LoadDel}{mm}
 {
  \seq_gset_split:cnn { g__nebu_del#1_seq } { , } { #2 }
 }
\NewDocumentCommand{\LoadPDel}{mm}
 {
  \seq_gset_split:cnn { g__nebu_pdel#1_seq } { , } { #2 }
 }
\cs_generate_variant:Nn \seq_gset_split:Nnn { c }

\int_new:N \l__nebu_columns_int
\int_new:N \l__nebu_pdeli_total_int
\int_new:N \l__nebu_pdelii_total_int
\int_new:N \l_nebu_countrows_int
\seq_new:N \g__nebu_deli_seq
\seq_new:N \g__nebu_pdeli_seq
\seq_new:N \g__nebu_delii_seq
\seq_new:N \g__nebu_pdelii_seq
\clist_new:N \g__nebu_deli_clist
\clist_new:N \g__nebu_pdeli_clist
\clist_new:N \g__nebu_delii_clist
\clist_new:N \g__nebu_pdelii_clist
\tl_new:N \l__nebu_preamble_tl
\tl_new:N \l__nebu_table_body_tl

\cs_new_protected:Npn \nebu_typeset_table:n #1
 {
  % Compute the number of inner columns
  \int_set:Nn \l__nebu_columns_int
   {
    \int_min:nn { #1 }
     {
      \int_max:nn { \seq_count:N \g__nebu_deli_seq }
                  { \seq_count:N \g__nebu_delii_seq }
     }
   }
  % Define the table preamble
  \tl_set:Nx \l__nebu_preamble_tl
   { l c *{ \int_to_arabic:n { \l__nebu_columns_int } } { c } c }
  % Compute the total for Del1
  \int_zero:N \l__nebu_pdeli_total_int
  \seq_map_inline:Nn \g__nebu_pdeli_seq
   { \int_set:Nn \l__nebu_pdeli_total_int { \l__nebu_pdeli_total_int + ##1 } }
  % Compute the total for Del2
  \int_zero:N \l__nebu_pdelii_total_int
  \seq_map_inline:Nn \g__nebu_pdelii_seq
   { \int_set:Nn \l__nebu_pdelii_total_int { \l__nebu_pdelii_total_int + ##1 } }
  % Start building the table contents
  \tl_clear:N \l__nebu_table_body_tl
  \tl_put_right:Nx \l__nebu_table_body_tl
   { \exp_not:N \multicolumn { \int_to_arabic:n { \l__nebu_columns_int + 2 } } { c } { } }
  \tl_put_right:Nn \l__nebu_table_body_tl { & Sum \\ \midrule }

  % Insert Del1
  \__nebu_insert_table_part:nn { deli } { Del~1 }
  \tl_put_right:Nn \l__nebu_table_body_tl { \midrule }
  % Insert Del2
  \__nebu_insert_table_part:nn { delii } { Del~2 }

  % Add total
  \tl_put_right:Nx \l__nebu_table_body_tl
   {
    \exp_not:N \midrule
    \exp_not:N \multicolumn
                { \int_to_arabic:n { 2 + \l__nebu_columns_int } }
                { r }
                { Total~antall~poeng }
    &
    \int_to_arabic:n { \l__nebu_pdeli_total_int + \l__nebu_pdelii_total_int }
    \exp_not:N \\
   }

  % Print the table
  \use:x{ \exp_not:N \begin{tabular}{\l__nebu_preamble_tl} }
  \toprule
  \l__nebu_table_body_tl
  \bottomrule
  \end{tabular}
}

\cs_new_protected:Npn \__nebu_insert_table_part:nn #1 #2
 {
  \int_set:Nn \l_nebu_countrows_int
   {
    \seq_count:c { g__nebu_#1_seq } / \l__nebu_columns_int
   }
  \int_step_inline:nnnn { 1 } { 1 } { \l_nebu_countrows_int }
   {
    % First line
    \int_compare:nTF { ##1 = 1 }
     {
      \tl_put_right:Nn \l__nebu_table_body_tl { #2 & Oppgave & }
     }
     {
      \tl_put_right:Nx \l__nebu_table_body_tl
       { \exp_not:N \cmidrule(lr){3-\int_to_arabic:n { \l__nebu_columns_int + 2 }} }
      \int_compare:nT { ##1 = 2 }
       {\tl_put_right:Nx \l__nebu_table_body_tl
         { \exp_not:N \cmidrule(l{3em}r)
            {\int_to_arabic:n { \l__nebu_columns_int + 2 }-
             \int_to_arabic:n { \l__nebu_columns_int + 3 }}
         }
       }
      \tl_put_right:Nn \l__nebu_table_body_tl { & & }
     }
    \int_step_inline:nnnn 
     { (##1 - 1)*\l__nebu_columns_int + 1 } 
     { 1 }
     { ##1 * \l__nebu_columns_int }
     {
      \tl_put_right:Nx \l__nebu_table_body_tl 
       { \seq_item:cn { g__nebu_#1_seq } { ####1 } & }
     }
     \tl_put_right:Nn \l__nebu_table_body_tl { \\ }
     % Second line
    \int_compare:nTF { ##1 = 1 }
     { \tl_put_right:Nn \l__nebu_table_body_tl { & Poeng & } }
     { \tl_put_right:Nn \l__nebu_table_body_tl { & & } }
     \int_step_inline:nnnn 
      { (##1 - 1)*\l__nebu_columns_int + 1 }
      { 1 }
      { ##1 * \l__nebu_columns_int }
      {
       \tl_put_right:Nx \l__nebu_table_body_tl
        { \seq_item:cn { g__nebu_p#1_seq } { ####1 } & }
      }
      \tl_put_right:Nx \l__nebu_table_body_tl
       {
        \int_compare:nT { ##1 = 1 }
         { \int_to_arabic:n { \use:c { l__nebu_p#1_total_int } } }
        \exp_not:N \\
       }
   }
 }

\ExplSyntaxOff

\setlength{\parindent}{0pt} % just for the example

\begin{document}

\TypesetTable

\bigskip

\TypesetTable[6]

\addtoDel{1}{1a1}{2}
\addtoDel{1}{1a2}{1}
\addtoDel{1}{1a3}{1}
\addtoDel{1}{1b}{2}
\addtoDel{1}{1c}{2}

\addtoDel{2}{a1}{2}
\addtoDel{2}{a2}{1}
\addtoDel{2}{a3}{1}
\addtoDel{2}{b}{2}
\addtoDel{2}{c}{2}
\addtoDel{2}{d1}{2}
\addtoDel{2}{d2}{2}
\addtoDel{2}{e}{2}
\addtoDel{2}{f1}{2}
\addtoDel{2}{f2}{2}
\addtoDel{2}{f4}{2}
\addtoDel{2}{f5}{2}

\end{document}

enter image description here


I got a bit bored with the formatting but

enter image description here

from

\maketab{
{1a1,1; 1a2,1;1a3,1;1b1,1;1b3,2;1c,2;1d1,2;1d2,2;1d3,0;1e1,2;1e2,2;
     1e3,2;1f,2;1g1,2;1g2,2;1g3,2;}
{2a,2;2b,2;2c,2;2d,2;2e,2;2f,2;3a1,2;3a2,2;3b,3;4a,2;4b,2;
     4c,2;4d,2;5a,1;5b,2;5c,2;6a,2;6b,2;}}

Full document:

\documentclass{article}
\usepackage{array}

\newcount\delcnt
\newcount\thistot
\newcount\tottot
\extrarowheight3pt
\makeatletter

\def\maketab#1{%
\delcnt\z@
\global\tottot\z@
\begin{tabular}{|c|p{20em}|c|}
\@maketab#1\relax
\multicolumn{2}{r|}{Total}&\the\tottot
\end{tabular}}

\def\@maketab#1{%
\ifx\relax#1%
\expandafter\@gobble
\else
\global\thistot\z@
\expandafter\@firstofone
\fi
{\global\advance\delcnt\@ne
Del \the\delcnt&%
\@maketb@#1\relax,;%
&
\global\advance\tottot\thistot
\the\thistot\\\hline\@maketab}}


\def\@maketb@#1,#2;{%
\ifx\relax#1\else
\global\advance\thistot#2\relax
\parbox[t]{2em}{\centering
\strut\ignorespaces#1\par\vskip2pt\hrule\vskip2pt
\strut\ignorespaces#2}\hfil\penalty\z@\hfilneg
\expandafter\@maketb@
\fi}

\makeatother

\begin{document}

\maketab{
{1a1,1; 1a2,1;1a3,1;1b1,1;1b3,2;1c,2;1d1,2;1d2,2;1d3,0;1e1,2;1e2,2;1e3,2;1f,2;1g1,2;1g2,2;1g3,2;}
{2a,2;2b,2;2c,2;2d,2;2e,2;2f,2;3a1,2;3a2,2;3b,3;4a,2;4b,2;4c,2;4d,2;5a,1;5b,2;5c,2;6a,2;6b,2;}}


\end{document}