Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

After a lot of trouble I've finally come pretty close to what I want to do. I now have a list that looks like this:

{"turen", {{"as", {{"lä", {}}}}, {"al", {{"säd", {}}, {"jäs", {}}}}, {"aj", {{"lä", {}}, {"säl", {}}, {"säd", {}}, {"läs", {}}}}, {"sa", {{"lä", {}}}}, 
  {"la", {{"säd", {}}, {"jäs", {}}}}, {"lä", {{"as", {}}, {"aj", {}}, {"sa", {}}, {"ja", {}}}}, {"ja", {{"lä", {}}, {"säl", {}}, {"säd", {}}, {"läs", {}}}}, 
  {"sal", {}}, {"säl", {{"aj", {}}, {"ja", {}}}}, {"säd", {{"al", {}}, {"aj", {}}, {"la", {}}, {"ja", {}}}}, {"läs", {{"aj", {}}, {"ja", {}}}}, 
  {"dal", {{"jäs", {}}}}, {"jäs", {{"al", {}}, {"la", {}}, {"dal", {}}}}, {"sälj", {}}, {"själ", {}}, {"läsa", {}}, {"ädla", {}}, {"dals", {}}, {"jäsa", {}}, 
  {"sälja", {}}, {"ädlas", {}}}}

Now the last thing I need to do is pick out all strings on the fourth level and concatenate them with their ancestors. There aren't any fourth level elements in my example list because those lists are huge. But imagine there is. If I know how to do it for two levels I can probably do it for three or four as well.

For example, if I concatenate up to the second level I should get a list that starts like

{"turen as lä","turen al säd" ...}
share|improve this question
1  
There is apparently some confusion as to your requirements. Are the answers below working as desired or do you need what rm-rf describes in the comments below mine? –  Mr.Wizard Jan 13 '13 at 3:34
1  
@Mr.Wizard I was being vague, but in the end I got good solutions that work for me anyway. I may have had in mind something like what rm-rf said but I don't particularly need it. So it's not a necessary criteria for a solution. Thanks. –  Pickett Jan 14 '13 at 1:00
add comment

2 Answers

up vote 11 down vote accepted

What you really want is a recursive traversal function, since what you constructed is a form of a prefix tree. Here is one possibility:

ClearAll[traverse];
traverse[prev_List, {s_String, {sub__}}] :=
  Map[traverse[{prev, s}, #] &, {sub}];

traverse[prev_List, {s_String, {}}] := 
  StringJoin[Riffle[Flatten[{prev, s}], " "]];

traverse[tree_List] := Flatten[traverse[{}, tree]];

The usage is

traverse[tree]

where tree is your nested list above. The result is a list of strings you are after:

(* {turen as lä,turen al säd,turen al jäs,<<34>>,turen sälja,turen ädlas} *)
share|improve this answer
    
I see that you interpreted this differently (and probably correctly). Try try again... –  Mr.Wizard Jan 13 '13 at 0:55
    
@Mr.Wizard Somehow we have different results. In my case, there are more strings, but all of them contain 3 parts (for this particular case). You have less strings but some of them containing more parts. –  Leonid Shifrin Jan 13 '13 at 0:57
    
Yes, after reading the question again I think I got it totally wrong. –  Mr.Wizard Jan 13 '13 at 0:57
1  
@Mr.Wizard To tell you the truth, I've been disappointed in the methods like those based on many nested Map,Thread etc. for a long time, as long as treatment of trees and other recursive structures is concerned. The biggest problem with them is that they realize recursion internally, while what is needed is a custom recursion tuned to a very particular data structure. But they work very well as a part of a recursive solution, making the code much shorter indeed. –  Leonid Shifrin Jan 13 '13 at 1:00
    
I think I've got it now. Can you confirm? –  Mr.Wizard Jan 13 '13 at 1:34
show 1 more comment

Second try:

dat = {"turen", {{"as", {{"lä", {}}}}, {"al", {{"säd", {}}, {"jäs", {}}}}, {"aj", {{"lä", \
{}}, {"säl", {}}, {"säd", {}}, {"läs", {}}}}, {"sa", {{"lä", {}}}}, {"la", {{"säd", {}}, \
{"jäs", {}}}}, {"lä", {{"as", {}}, {"aj", {}}, {"sa", {}}, {"ja", {}}}}, {"ja", {{"lä", \
{}}, {"säl", {}}, {"säd", {}}, {"läs", {}}}}, {"sal", {}}, {"säl", {{"aj", {}}, {"ja", \
{}}}}, {"säd", {{"al", {}}, {"aj", {}}, {"la", {}}, {"ja", {}}}}, {"läs", {{"aj", {}}, \
{"ja", {}}}}, {"dal", {{"jäs", {}}}}, {"jäs", {{"al", {}}, {"la", {}}, {"dal", {}}}}, \
{"sälj", {}}, {"själ", {}}, {"läsa", {}}, {"ädla", {}}, {"dals", {}}, {"jäsa", {}}, \
{"sälja", {}}, {"ädlas", {}}}};

Then:

dat //. {{s_, {}} :> s, {x_, y_List} :> Thread[x ~~ " " ~~ y]};

Flatten[Thread /@ %]
turen as lä
turen al säd
turen al jäs
turen aj lä
turen aj säl
turen aj säd
turen aj läs
turen sa lä
turen la säd
turen la jäs
turen lä as
turen lä aj
turen lä sa
turen lä ja
turen ja lä
turen ja säl
turen ja säd
turen ja läs
turen sal
turen säl aj
turen säl ja
turen säd al
turen säd aj
turen säd la
turen säd ja
turen läs aj
turen läs ja
turen dal jäs
turen jäs al
turen jäs la
turen jäs dal
turen sälj
turen själ
turen läsa
turen ädla
turen dals
turen jäsa
turen sälja
turen ädlas
share|improve this answer
1  
Looks like you've nailed it, +1. Generally, I found recursion to be more powerful than rules + ReplaceRepeated, but here apparently the latter is enough. Nice solution! –  Leonid Shifrin Jan 13 '13 at 1:39
1  
I think the question asked for a way to be able to join words up to some level X, not all the way. Or rather, start with an inner string at level X and prepend all its predecessors. –  rm -rf Jan 13 '13 at 2:24
    
@rm-rf what is supposed to happen to the deeper elements then? –  Mr.Wizard Jan 13 '13 at 2:39
    
My interpretation was that the deeper ones will be ignored. Taking the above example, if they wanted to concatenate for "level 1" with its ancestors (taking "turen" to be level 0), then they'd get {"turen as", "turen al", "turen aj"...}. For level 2, they'd get the above list without the two word strings (i.e. "turen själ", "turen jäsa",...) –  rm -rf Jan 13 '13 at 2:55
add comment

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.