# Flatten nested lists

I have a list as follows

lis= {a, {{{b}, {c,d,e}}, {{f}, {g,h,i}}}}


which I would like to flatten to

flattenLis={a,{b,c,d,e},{f,g,h,i}}


Does anyone have a hint. All my flatten attempts did not work. Thanks

Here is an approach where I apply the flattening "from the bottom up" (negative level specification). This works by operating on {lis} instead of lis, in order to have sufficiently many levels even when there's no list wrapping an element, such as a:

Flatten[Map[Flatten, {lis}, {-3}], 2]

(* ==> {a, {b, c, d, e}, {f, g, h, i}} *)


My approach also works for this example:

lis2 = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}}}, b};

Flatten[Map[Flatten, {lis2}, {-3}], 2]

(* ==> {a, {b, c, d, e}, {f, g, h, i}, b} *)

• According your idea, {#1, Sequence @@ #2} & @@ Map[Flatten, lis, {-3}] also works:) – xyz Mar 24 '15 at 1:39
• There is a potential problem with this approach. This will fail if the elements are not atomic, e.g. if b = Sqrt[2];. My method does not fail in that circumstance, nor does it fail on lis2 despite your assertion. – Mr.Wizard Mar 24 '15 at 3:46
• @Mr.Wizard Yes, the bottom-up approach can only work if the leafs are atomic - I guess maybe one could ensure that using Block if the entries are at least named by symbols that can be blocked. – Jens Mar 24 '15 at 4:19
• @ShutaoTang Yes, but your Slot based approach wouldn't work with my lis2. Anyway, at this point the OP certainly has a lot of methods to choose from... – Jens Mar 24 '15 at 4:31

Not sure how general it will be:

{#, ## & @@ Flatten /@ #2} & @@ lis

{a, {b, c, d, e}, {f, g, h, i}}

• Same comment here as for @Mr.Wizard. – Jens Mar 23 '15 at 22:50
• Could you @Kuba give some explanation here? :). – xyz Mar 24 '15 at 1:19
• I see. 1)  {#1, Flatten /@ #2} & @@ lis(==>{a, {{b, c, d, e}, {f, g, h, i}}}) 2) {#, ## & @@ #2} & @@ % (*==> {a, {b, c, d, e}, {f, g, h, i}}*) – xyz Mar 24 '15 at 5:00
• @Jens sure but that is not the question. :) – Kuba Mar 24 '15 at 6:58

One approach:

MapAt[Flatten, lis, {2, All}] ~FlattenAt~ 2

{a, {b, c, d, e}, {f, g, h, i}}


Hopefully some combination of MapAt, Flatten, and FlattenAt will work for any structure you have.

• This works for the example, but not for lis = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}}}, b}. I upvoted anyway, since the question doesn't specify what generalizations are desirable. – Jens Mar 23 '15 at 22:49
• I discovered that this solution was restricted in V8.MapAt::psl: "Position specification {2,All} in MapAt[Flatten,{a,{{{b},{c,d,e}},{{f},{g,h,i}}}},{2,All}] is not an integer or a list of integers. " – xyz Mar 24 '15 at 1:26
• @ShutaoTang That is correct; support for All and Span within MapAt was (silently) introduced in version 9; see: (31173). There are alternatives in that Q&A that will work in earlier versions. – Mr.Wizard Mar 24 '15 at 3:39
• @Jens I'm not sure what you mean; using your lis I get {a, {b, c, d, e}, {f, g, h, i}, b} -- what else do you want? – Mr.Wizard Mar 24 '15 at 3:40
• @Mr.Wizard Oh, I know what happened: I was on MMA version 8, and tested my lis2 with your method. It errored out, but now I see it works in version 10. In version 8, your answer doesn't even work with the original lis... It's because MapAt in version 8 doesn't seem to accept position specification All. That change isn't mentioned in the version-10 documentation. – Jens Mar 24 '15 at 4:12

Also:

lis = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}}}};
Fold[Apply[## &, #, {#2}] &, lis, {1, 2}]
(* {a, {b, c, d, e}, {f, g, h, i}} *)


And ... ♯ = {## & @@ #, ## & @@@ #2} & @@ ({##}) &'s close relative:

♭ = ## & @@@ (## & @@@ {## & @@@ # & /@ #} & /@ #) &;


Examples:

♭ @ lis
(* {a, {b, c, d, e}, {f, g, h, i}} *)

lis2 = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}, {x}}}, b};
♭ @ lis2
{a, {b, c, d, e}, {f, g, h, i, x}, b}

• Your last one is probably a quote from the pirate in Asterix&Obelix, right? But it doesn't work on lis = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}}}, b}. – Jens Mar 23 '15 at 22:40
• @Jens, right! and Getafix says there is a fix:) – kglr Mar 23 '15 at 23:17
• If anyone looks at the edit history, they will get dizzy... I could still annoy you with this example, though: lis = {a, {{{b}, {c, d, e}}, {{f}, {g, h, i}, {x}}}, b}; where I added an {x} together with the {f}. Your first approach works, the second still doesn't. – Jens Mar 23 '15 at 23:22
• @Jens, deleted the quotes from the pirate and getafix:) Actually, i am surprised the first one works beyond op's simple example. – kglr Mar 23 '15 at 23:28
• I didn't really intend to make you delete the other solution - it was fun to look at... – Jens Mar 24 '15 at 16:53

Another approach is rule replacement, which can be restricted to a specific level.

In[16]:=Replace[lis, l_List :> Sequence @@ Flatten[l], {1}] === flattenList

Out[16]=True


I didn't see an easy way to make this one work without Sequence.

I'm not sure I really understand how the example is to be generalised, but this removes all List heads at level 2 and 4:

ReplacePart[lis, Position[lis, List, {#}] & /@ Join[2, 4] -> Sequence]

(* {a, {b, c, d, e}, {f, g, h, i}} *)