Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I would like to transform the following list

data={{0,A1,1},{1,C1,2},{1,C2,3},{3,C4,1},{0,A2,1},{1,C2,1},{0,A1,4},{1,C1,1},{2,C2,1}}

into another list like this

output={{A1,1,0,A1,1},{A1,1,1,C1,2},{A1,1,1,C2,3},{A1,1,3,C4,1},{A2,1,0,A2,1},{A2,1,1,C2,1},{A1,4,0,A1,4},{A1,4,1,C1,1},{A1,4,2,C2,1}}

Basically, the first column indicates the level,0 being the head level of a bill of material and would like to put the header item and header quantity as columns besides the components for easier computation further along.

Thanks.

share|improve this question
3  
This could use a better title... – J. M. Nov 3 '12 at 5:17
Indeed @J.M., the title should be better, but couldn't come up with one. What would your recommendation be? – PatoCriollo Nov 3 '12 at 13:20
Well, the real problem that you're trying to solve ought to be reflected in the title... – J. M. Nov 3 '12 at 13:32

3 Answers

up vote 4 down vote accepted

The first thing you should do is collect all the elements under a single header into their own sublists. Assuming the "levels" are always in increasing order, this will do the job:

sublists = Split[data, First@#1 <= First@#2 &]
(* {{{0, A1, 1}, {1, C1, 2}, {1, C2, 3}, {3, C4, 1}},
    {{0, A2, 1}, {1, C2, 1}},
    {{0, A1, 4}, {1, C1, 1}, {2, C2, 1}}} *)

Then for each sublist, you can just take its header and join it to all its elements.

formatted = Function[list, Join[Rest@First@list, #] & /@ list] /@ sublists
(* {{{A1, 1, 0, A1, 1}, {A1, 1, 1, C1, 2}, {A1, 1, 1, C2, 3}, {A1, 1, 3, C4, 1}},
    {{A2, 1, 0, A2, 1}, {A2, 1, 1, C2, 1}},
    {{A1, 4, 0, A1, 4}, {A1, 4, 1, C1, 1}, {A1, 4, 2, C2, 1}}} *)

In the end you probably also want to flatten the sublists.

output = Flatten[formatted, 1]
(* {{A1, 1, 0, A1, 1}, {A1, 1, 1, C1, 2}, {A1, 1, 1, C2, 3}, {A1, 1, 3, C4, 1},
    {A2, 1, 0, A2, 1}, {A2, 1, 1, C2, 1}, {A1, 4, 0, A1, 4}, {A1, 4, 1, C1, 1},
    {A1, 4, 2, C2, 1}} *)

Of course, all of this can be pulled into a single expression if you prefer:

output = Flatten[
  Function[list, Join[Rest@First@list, #] & /@ list] /@ 
   Split[data, First@#1 <= First@#2 &], 1]
share|improve this answer

Guessing the "header" data from the two lists in your question, and making non-numeric elements strings,

data = {{0, "A1", 1}, {1, "C1", 2}, {1, "C2", 3}, {3, "C4", 1}, {0,"A2", 1}, 
{1, "C2", 1}, {0, "A1", 4}, {1, "C1", 1}, {2, "C2", 1}};
headers = {{"A1", 1}, {"A1", 1}, {"A1", 1}, {"A1", 1}, {"A2", 1}, {"A2", 1},
{"A1", 4}, {"A1", 4}, {"A1", 4}};

you can use

MapThread[Join, {headers, data}];
(* or *)  Join @@@ Thread[{headers, data}]
(* or *)  Flatten /@ Thread@{headers, data}
(* or *)  Transpose[Flatten[Transpose /@ {headers, data}, 1]]
(* or *)  Thread[Flatten[Transpose /@ {headers, data}, 1]]

All give

{{"A1", 1, 0, "A1", 1}, {"A1", 1, 1, "C1", 2}, {"A1", 1, 1, "C2", 3}, 
 {"A1", 1, 3, "C4", 1}, {"A2", 1, 0, "A2", 1}, {"A2", 1, 1, "C2", 1},
 {"A1", 4, 0, "A1", 4}, {"A1", 4, 1, "C1", 1}, {"A1", 4, 2, "C2", 1}}
share|improve this answer
I think the header is supposed to be the latest entry with first element 0. – Rahul Narain Nov 3 '12 at 7:43
@Rahul, I think you are right ... and that makes it a much more interesting question. – kguler Nov 3 '12 at 8:58
@Rojo/@kgluger/@Rahul, thanks so much for taking a stab at the problem. Just to give some context, the toy problem below is an overall simplification of importing and processing some ascii dumps of 200+ report. In the files you would have a header structure, and then a list of variable number components, header and components with each with its own field structure. I was successful in manipulating the files and dumping everything into a single list and this is where I got stuck. It is still very difficult for me to get away from procedural language structure, – PatoCriollo Nov 3 '12 at 13:27
which is what I finally used to get things done quickly, but I want to avoid the use of do's and for's in Mathematica. – PatoCriollo Nov 3 '12 at 13:29

If what @kguler interpreted is correct, then you could do

Rest@FoldList[
  Join[If[First@#2 == 0, Rest@#2, #1~Take~2], #2] &, {Null, "Default", Indeterminate},
  data]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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