Flatten at a certain level
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]]
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_] :=
Internal`InheritedBlock[{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.
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}]