11
$\begingroup$

As the title says, I would like to flatten all inner lists, excluded the ones that do not have sublists. For example, from

lis = {a, {b, {d, f}}, {{c, k, {h, l}}, e}, {{{{a}}}}};

I would like to have

myFlatten[lis]

{a, b, {d, f}, c, k, {h, l}, e, {a}}

I have a solution, but probably is inefficient and not elegant. The steps are the following:

  • change the Head of all List subparts that do not have members of type List, to something else, say myList
  • Flatten the resulting expression
  • change back myList to List

this is my implementation:

notListQ[z_] := Head[z] =!= List;

myFlatten[list_List] := Module[{myList, tempList},
  tempList = list /. List[y__?notListQ] -> myList[y];
  tempList = Flatten[tempList];
  tempList /. myList -> List
]

This obviously can be shortened to

myFlatten[list_List] := Module[{myList},
  Flatten[list /. List[y__?notListQ] -> myList[y]] /. myList -> List
]

Any errors in my implementation?
Better solutions?

Thank you

$\endgroup$
12
$\begingroup$
ReleaseHold[Flatten[MapAt[Hold, lis, Position[lis, _List?VectorQ]]]]

{a, b, {d, f}, c, k, {h, l}, e, {a}}

$\endgroup$
  • 1
    $\begingroup$ Another variant is ReleaseHold @ Flatten @ Replace[lis, l_List :> Hold[l], {-2}] $\endgroup$ – Carl Woll Sep 26 '18 at 16:33
  • $\begingroup$ Thank you, I didn't know about VectorQ, and never understood well the semantic meaning of Hold and ReleaseHold. $\endgroup$ – enzotib Sep 26 '18 at 16:46
  • 1
    $\begingroup$ Yet another variant: ReleaseHold[Flatten[Map[Hold, lis, {-2}]]] $\endgroup$ – J. M. is in limbo Sep 26 '18 at 16:54
  • $\begingroup$ @J.M.issomewhatokay. I like the simplicity of your solution $\endgroup$ – enzotib Sep 26 '18 at 17:38
6
$\begingroup$
Apply[## &, lis, -3]
Apply[Sequence, lis, -3] (* thanks J.M. *)
Map[## & @@ # &, lis, -3]
Replace[lis, {a__} :> a, -3]
FlattenAt[#, Position[#, {__}, -3]]& @ lis

all give

{a, b, {d, f}, c, k, {h, l}, e, {a}}

Also, with

parts = Join @@ Most /@ Rest @ GatherBy[Position[lis, List], First];

you can use ReplacePart,MapAt, FlattenAt or Part assignment:

ReplacePart[lis, parts -> Sequence]
MapAt[Sequence &, lis, parts]
FlattenAt[lis, Most /@ parts]
Module[{l = #}, (l[[##]] = Sequence) & @@@ #2; l] &[lis, parts]

{a, b, {d, f}, c, k, {h, l}, e, {a}}

Finally, you can do in-place assignment:

(lis[[##]] = Sequence) & @@@ parts; lis

{a, b, {d, f}, c, k, {h, l}, e, {a}}

$\endgroup$
  • 1
    $\begingroup$ Another one: Apply[Sequence, lis, -3] $\endgroup$ – J. M. is in limbo Sep 26 '18 at 19:33
  • $\begingroup$ @J.M. yes! Thank you. $\endgroup$ – kglr Sep 26 '18 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.