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.

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.

share|improve this question
    
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 :) –  Leonid Shifrin Jan 27 '12 at 12:22
1  
Your desired output should be {{1, 2, 3, 4, 5, 11}, {6, 7, 8, 9, 10, 12}}, right? –  Thomas Jan 27 '12 at 12:40
    
@Thomas Right. It's hidden somewhere in the mid of the post. –  Sjoerd C. de Vries Jan 27 '12 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}] –  Sjoerd C. de Vries Jan 27 '12 at 17:54
    
@sjoerd what I meant with my comment is that you have one bracket too much. I don't have edit privilege. –  Thomas Jan 28 '12 at 15:58
add comment

2 Answers

up vote 2 down vote accepted

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.

share|improve this answer
add comment

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]]
share|improve this answer
    
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. –  Sjoerd C. de Vries Jan 27 '12 at 13:40
    
@SjoerdC.deVries, does the edit help you? –  user21 Jan 27 '12 at 14:05
    
Thanks, I appreciate the effort. I feel the Map version would be a bit simpler, though. –  Sjoerd C. de Vries Jan 27 '12 at 14:17
    
And I think that's the reason why FlattenAt is not such a widely used command. –  user21 Jan 27 '12 at 14:21
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.