5
$\begingroup$

Today I ran into matrices like this one:

{
 {        {b, 1}, {c, 0}        },
 {{a, 1}, {b, 2}, {c, 0}, {d, 9}},
 {{a, 3}, {b, 7},         {d, 5}},
 {{a, 6}                        },
 {                        {d, 7}}
}

I need the transformation into this form:

{
 {{a, 1}, {b, 1}, {c, 0}, {d, 0}},
 {{a, 1}, {b, 2}, {c, 0}, {d, 9}},
 {{a, 3}, {b, 7}, {c, 7}, {d, 5}},
 {{a, 6}, {b, 6}, {c, 6}, {d, 6}},
 {{a, 7}, {b, 7}, {c, 7}, {d, 7}}
}

Didn't find a presentable solution. Please help

$\endgroup$
  • 1
    $\begingroup$ How are the 'default' numerical values chosen? How do we know to propagate from the left or the right? Is the first element of each pair always an alphabetically increasing single-letter symbol? Is the width specified or inferred from the row with the lexically latest symbol? $\endgroup$ – 2012rcampion Apr 2 '15 at 19:33
  • $\begingroup$ Thank you very much for editing. As to your question: Both answers deliver the desired result. $\endgroup$ – eldo Apr 2 '15 at 21:34
2
$\begingroup$

This is a generalized solution, should be pretty snappy:

filler[mat_, blank_] := Module[
   {cols = Flatten[Cases[#, {i_, _} :> i, 1, 1] & /@ Transpose@mat,1], 
    f, tmp, x, b},
   f[x_, blank] := x;
   f[_, b_] := b;
   tmp = FoldList[f, 
        FoldList[f, #][[-1 ;; 1 ;; -1]]][[-1 ;; 1 ;; -1]] & /@ mat;
   MapIndexed[(tmp[[All, First@#2, 1]] = #1) &, cols];
   tmp];

Example test on 10x10 randomly generated array:

t // MatrixForm

enter image description here

filler[t, "x"] // MatrixForm

enter image description here

For arrays in the OP form (missing entries with no "blank" indicator, but known column sets), a simple pre-processing can be done to bring them into a form usable by filler:

preproc[array_, cols_, blank_] := 
 Module[{colsidx = Range@Length@cols, rules, 
   c = ConstantArray[blank, Length@cols]},
  rules = Dispatch[Thread[Rule[cols, colsidx]]];
  Module[{t = c, p = #[[All, 1]] /. rules}, t[[p]] = #; t] & /@ array]

Use:

tt//MatrixForm

enter image description here

filler[preproc[tt, {a, b, c, d, e, f, g, h, i, j}, "xx"], "xx"] // MatrixForm

enter image description here

I've preemptively modified filler per OP's comments re: the actual format of inputs (simple change to the column tracking list), perhaps this is what is intended:

Input:

ttt//MatrixForm

enter image description here

filler[preproc[ttt, {{2015, 12, 1}, {2015, 12, 2}, {2015, 12, 3}, {2015, 12, 4}, {2015, 12, 5}}, "x"], "x"] // MatrixForm

enter image description here

$\endgroup$
  • $\begingroup$ Unfortunately this doesn't function with my data. Please replace a with {2015,1,1}, b with {2015,1,2} etc. The "keys" are dates. I'm sorry for not having asked my question correctly (I wanted to keep it simple). $\endgroup$ – eldo Apr 3 '15 at 9:48
  • $\begingroup$ @eldo since you claim the other answers produce your desired result, use those. I'll leave this as is, since it does what is asked in the question, and more efficiently by far than those. I suggest in the future you not try to second-guess the ability of readers to comprehend scenarios, and "simplifying" things into completely different questions, causing wasted time and effort. $\endgroup$ – ciao Apr 3 '15 at 11:25
  • $\begingroup$ I didn't claim this. The other answers don't function either. Your snappy answer came closest. I tried for two hours to adapt your code, but to no avail. I already excused myself for the wasted time. Please help in case you see an easy fix :) $\endgroup$ – eldo Apr 3 '15 at 11:41
  • $\begingroup$ @eldo: It appears perhaps I misinterpreted your " Both answers deliver the desired result" comment (when there were only two answers), and commenting that "...speed isn't important here." on the highest voted answer without even mentioning it doesn't work, so of course one would be justified to presume it works. Commenting on an answer that's broken, without noting that, goes against the whole idea of the site - how can a reader possibly know which answers are useful? In any case, please update your OP with a precise example of input, desired output, and any "rules" for the conversion. $\endgroup$ – ciao Apr 3 '15 at 20:32
  • $\begingroup$ @eldo: See update - I went ahead and made some assumptions, will look at your updated OP when it's... updated. $\endgroup$ – ciao Apr 3 '15 at 20:46
4
$\begingroup$

Let l be your list.

step1 = {a, b, c, d} /. ( Rule @@@ # & /@ l) /. a | b | c | d -> "x"

{{"x", 1, 0, "x"}, {1, 2, 0, 9}, {3, 7, "x", 5}, {6, "x", "x",
"x"}, {"x", "x", "x", 7}}

fill[l_] := l //. {
   {x___, PatternSequence[c_?NumericQ, "x"], y___} :> {x, c, c, y},
   {x___, PatternSequence["x", c_?NumericQ], y___} :> {x, c, c, y}
   }
step2 = fill /@ step1

{{1, 1, 0, 0}, {1, 2, 0, 9}, {3, 7, 7, 5}, {6, 6, 6, 6}, {7, 7, 7, 7}}

step3 = step2 /. {v1_, v2_, v3_, v4_} :> {{a, v1}, {b, v2}, {c, v3}, {d, v4}}

{{{a, 1}, {b, 1}, {c, 0},...

The fill function is a modified version Arte's answer here, one of my own very old questions.

$\endgroup$
  • $\begingroup$ There are much faster ways than any of those answers... but still fill is pretty... +1 $\endgroup$ – ciao Apr 2 '15 at 20:29
  • $\begingroup$ i forgot to mention that speed isn't important here. My matrix has a maximum of 10 columns and always 299 rows. $\endgroup$ – eldo Apr 2 '15 at 21:18
1
$\begingroup$

Let m be your ragged matrix.

fill[row_, init_] := If[
  MemberQ[First /@ row, First@init],
  row,
  Module[
    {r, p},
    r = Sort[Append[row, init]];
    p = First@FirstPosition[r, init];
    r /. x -> Last@r[[If[p == 1, Plus, Subtract][p, 1]]]
  ]
];
Fold[fill, #, {{a, x}, {b, x}, {c, x}, {d, x}}] & /@ m
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.