# Flatten at a certain level

In an earlier question the brainteasing fourth syntax variant of Flatten was discussed. I see that with

Flatten[{{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9, 10}}}, {{1}, {2, 3}}]


I can Flatten the lists at level 2 (i.e., Merge {1, 2, 3} with {4, 5}, and {6, 7} with {8, 9, 10}) to

{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}, something that I expected Flatten to be able to do with the usual level specification. But that convention doesn't work here.

Flatten[{{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9, 10}}}, {2}] returns {{{1, 2, 3}, {6, 7}}, {{4, 5}, {8, 9, 10}}}

With that introduction, now to my question: How would I use Flatten to flatten the slightly differing

{{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}}


to

{{1, 2, 3, 4, 5, 11}, {6, 7, 8, 9, 10, 12}}?


If that's not possible I'd have to resort to using an additionally Map, but I really would like to avoid that, as I just feel that Flatten or another single function ought to be able to do this on its own.

In this case, a simple

Flatten /@ {{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}}


would do, and since Map does follow the level specification conventions I can use it to Flatten other depths in more complex constructions.

• I don't think you can do this using Flatten alone, without using Map or something similar. This time though, I wish I am wrong :) Jan 27, 2012 at 12:22
• Your desired output should be {{1, 2, 3, 4, 5, 11}, {6, 7, 8, 9, 10, 12}}, right? Jan 27, 2012 at 12:40
• @Thomas Right. It's hidden somewhere in the mid of the post. Jan 27, 2012 at 12:58
• @R.M I don't think this will work, because the 3rd argument of Fold isn't a level specification.Try for instance with this list and depth 3: list={{{{1, {2}, 3}, {4, 5}, {11}}, {{6, 7}, {8, {9, 10}}, {12}}}};flatten2[list, {3}] and compare with Map[Flatten, list, {3}] Jan 27, 2012 at 17:54
• @sjoerd what I meant with my comment is that you have one bracket too much. I don't have edit privilege. Jan 28, 2012 at 15:58

Ok, I will give it a shot, although what follows is mostly a guess, and I also may be wrong.

### Why this does not work (a guess)

I think, what you ask can not be achieved with just Flatten. And the reason for this is that there seems to be no way for the syntax you propose to coexist with the syntax explained in the question you linked. So, the problem is, that while e.g. this code is ligitimate:

Flatten[{{{1, 2, 3}, {6, 7}}, {{4, 5}, {8, 9, 10}}, {11, 12}}, {1}]

(*
==>  {{{1, 2, 3}, {6, 7}}, {{4, 5}, {8, 9, 10}}, {11, 12}}
*)


the syntax we used there means not what you'd like it to be in this case. I can only guess that this design decision was motivated by considering this possibility to be easily implemented using Map (for those who need it), while the one that currently is there for this syntax to be less trivial and not easily replicated.

### Making it work through custom environments

If you want to frequently use Flatten with the semantics you mentioned, I suggest to create a lexical or dynamic environment where you will replace the existing semantics with this one. Here is a dynamic environment which will do that:

ClearAll[withListableFlatten];
SetAttributes[withListableFlatten, HoldAll];
withListableFlatten[code_] :=
InternalInheritedBlock[{Flatten},
Unprotect[Flatten];
Flatten[lst_, levspec_List] := Map[Flatten, lst, levspec];
Protect[Flatten];
code];


and now:

withListableFlatten[
Module[{
test = {{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}},
levSpec = {1}},
Flatten[test, levSpec]
]]

(*
==> {{1, 2, 3, 4, 5, 11}, {6, 7, 8, 9, 10, 12}}
*)


where I used Module to illustrate that the new syntax will take effect for an arbitrary code enclosed in this wrapper, and all the way down the execution stack in this code. A lexical environment will be much easier to write in this case:

ClearAll[withListableFlattenLex];
SetAttributes[withListableFlattenLex, HoldAll];
withListableFlattenLex[code_] :=
ReleaseHold[
Hold[code] /. HoldPattern[Flatten[l_, lev_]] :>
Map[Flatten, l, lev]]


and you can check that it will give the same result for the above example. The difference is that in this case, only the explicit entries of Flatten in code will be affected.

As a side note, a good thing about dynamic environments is that they can be easily combined / nested, with rather predictable behavior in terms of how they interact, because they change behavior at run-time only (which is a late stage). The bad thing about them is that they affect all the code down the execution stack, and this makes them less suitable for writing say higher-order functions, or any functions which accept arbitrary user's code. Lexical environments are safer in this respect, but so far Mathematica lacks a genuine macro system which would both be natural to use, and will make their composition easier.

Your subject line starts with "Flatten at..."

FlattenAt[{{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}}, {{1,
1}, {1, 2}, {2, 1}, {2, 2}}]


I don't think this is possible for Flatten.

Edit : Here is a programmatic way to get to the positions:

l = {{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}};
FlattenAt[l, Position[l, _?(Depth[#] == 2 &), Infinity]]

• I realized that I could use this, but that wouldn't be an option if I wanted to do this if my list was much bigger. Having to specify all the subparts would be prohibitive cumbersome. Jan 27, 2012 at 13:40
– user21
Jan 27, 2012 at 14:05
• Thanks, I appreciate the effort. I feel the Map version would be a bit simpler, though. Jan 27, 2012 at 14:17
• And I think that's the reason why FlattenAt is not such a widely used command.
– user21
Jan 27, 2012 at 14:21

Transforming

{{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}}


into

{{1, 2, 3, 4, 5, 11}, {6, 7, 8, 9, 10, 12}}


requires the replacement of lists at levels {2} and {3} by mere sequences. Instead of Flatten[nestedList, {levelsToDelete}] use something like Apply[Sequence, nestedList, {levelsToDelete}].

For example:

Apply[Sequence, {{{1, 2, 3}, {4, 5}, 11}, {{6, 7}, {8, 9, 10}, 12}}, {2, 3}]
`