# Filling a matrix with a list of lists

I have a list of lists with different lengthes:

{{a1,a2},{b1,b2},{c1,c2,c3},...}


Now I want to create a matrix the following way:

{{       0,        0, f[b1,a1], f[b2,a1], f[c1,a1], f[c2,a1], f[c3,a1],...},
{       0,        0, f[b1,a2], f[b2,a2], f[c1,a2], f[c2,a2], f[c3,a2],...},
{f[a1,b1], f[a2,b1], 0       , 0       , f[c1,b1], f[c2,b1], f[c3,b1],...},
{f[a1,b2], f[a2,b2], 0       , 0       , f[c1,b2], f[c2,b2], f[c3,b2],...},
{f[a1,c1], f[a2,c1], f[b1,c1], f[b2,c1], 0       , 0       , 0       ,...},
{f[a1,c2], f[a2,c2], f[b1,c2], f[b2,c2], 0       , 0       , 0       ,...},
{f[a1,c3], f[a2,c3], f[b1,c3], f[b2,c3], 0       , 0       , 0       ,...},
{                                   ...                                  }}


If it weren't for those zero-blocks I could simplify use flatten on my nested list, but I somehow need to "remember" the structure it. Note that a1,.. are just placeholders to better show what I mean. In reality a1 could be equal to b2 for example. Maybe one could do this in two steps and set the zeros in the second one. But I'm not sure how to do this without for-loops either.

blocks[l_List, f_] := Module[{m},
m = Transpose@Outer[f, #, #] &@Flatten[l];
(m[[#, #]] = 0) & /@
Span @@@ (# + {1, 0} & /@ Partition[{0}~Join~Accumulate[Length /@ l], 2, 1]);
m
]


blocks[{{a1, a2}, {b1, b2}, {c1, c2, c3}}, f] // MatrixForm


blocks[{{a1, a2, a3}, {b1}, {c1, c2}}, f] // MatrixForm


blocks[l_List, f_] := Map[f @@ # &,
Module[{m = 0, F = Flatten[l], Q},
ReplacePart[Table[Q[i, j], {j, F}, {i, F}],
Flatten[Tuples[#, 2] & /@ Map[++m &, l, {2}], 1] -> 0]], {2}]