7
$\begingroup$

this is a weird question, but I read the following line of code:

Select[Flatten[Module[{x}, x = #;
       Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph, 1], 
   Length@# > 1 &];

I was wondering if there is way to write this without the symbols or better if in a simpler way. I know that & means function and /@ means Map. But, I am struggling to write the code without these. Any help is appreciated. Many thanks

$\endgroup$
3
  • 1
    $\begingroup$ I hesitate to post this, but maybe seeing the prefix forms versus the infix forms will actually help. Select[Flatten[Map[Function[Module[{x}, x = #; Map[Function[Join[x[[1]], #]], x[[2 ;; -1]]]]], igraph], 1], Function[Length[#] > 1]]. But there is almost certainly a better way to rewrite this entire code. If you could explain what you want to achieve,and also what igraph is expected to be, then we could make progress toward better code. $\endgroup$
    – lericr
    Commented Mar 10, 2022 at 18:25
  • 1
    $\begingroup$ But, I am struggling to write the code without these..... Could you please share the code that you have written? $\endgroup$
    – Syed
    Commented Mar 10, 2022 at 18:34
  • 1
    $\begingroup$ First identify the inner-most construct: Module[{x}, x = #; Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph. note x=# which means each item in the array igraph must be itself an array but the Join operator takes arrays so looks like igraph has the form {{{a},{b},{c}},{{d},{e},{f}}} and so forth. Then analyze the next layer from this layer then the next. Try igraph = {{{1}, {2}, {3}}, {{4}, {5}, {6}}, {{7}, {8}, {9}}} then Module[{x}, x = #; Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph $\endgroup$
    – josh
    Commented Mar 10, 2022 at 18:40

2 Answers 2

8
$\begingroup$

let's use curry

one by one.

Flatten[Module[{x}, x = #; Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph, 1] // Select[Length@# > 1 &];
igraph // 
Map[
    Module[{x}, x = #;
    x[[2 ;; -1]] // Map[Join[x[[1]],#]&]
    ]&
] //
Flatten[# , 1]& // 
Select[Length@# > 1 &];

now it seems easier to understand.

read it:

  1. take an element igraph,

  2. map a function on it.

    this function is Module[{x}, x = #; x[[2 ;; -1]] // Map[Join[x[[1]],#]&] ]&,

  3. Flatten[# , 1]& the result,

  4. select elements whose length > 1.

$\endgroup$
1
7
$\begingroup$

Mathematica's FullForm writes an expression without any abbreviations, not even ones you wish it would use:

Hold[Select[Flatten[Module[{x}, x = #;
       Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph, 1], 
   Length@# > 1 &]] // FullForm
(*
Hold[Select[
  Flatten[
   Map[Function[
     Module[List[x], 
      CompoundExpression[Set[x, Slot[1]], 
       Map[Function[Join[Part[x, 1], Slot[1]]], 
        Part[x, Span[2, -1]]]]]], igraph], 1], 
  Function[Greater[Length[Slot[1]], 1]]]]
*)

The TreeForm[expr] and ExpressionTree[expr] make the nested [] easier to read in theory, but the tree quickly gets too large to read.

Here's a way to display the nested structure, in which I took the liberty of abbreviating a few commands:

nested // ClearAll;
nested // Attributes = {HoldAll};
myGrid = Grid[#, Alignment -> {Left, Top}, 
    Dividers -> {{{True, {False}}, 1 -> Pink}, False}] &;

(* Optional abbreviations *)
nested[e_Slot] := myGrid@{{HoldForm[e]}}; (* Slot[1]=#1, Slot[2]=#2... *)
nested[e_Part] := myGrid@{{HoldForm[e]}}; (* Part[x, 1]=x[[1]]... *)
(*nested[CompoundExpression[a__]]:=Module[{$list},
  myGrid[Riffle[
  Thread[{, nested /@ Hold[a] // Apply@List}],
  $list] /. $list -> {, ";"}]
];*)
nested[(h : Block | Module)[v_, a_]] := 
  myGrid[{ (* 1st arg List[x,y]={x,y} *)
    {Row[{h, "["}], SpanFromLeft},
    {, myGrid@{{HoldForm[v]}}},
    {, nested[a]},
    {"]"}}];
nested[(h : Set | SetDelayed)[v_, a_]] := 
  myGrid[{ (* v=... or v:=... *)
    {HoldForm[h[v, ""]], SpanFromLeft},
    {, nested[a]}}];

(* Main definitions *)
nested[h_[a___]] := myGrid[{
    {Row[{h, "["}], SpanFromLeft},
    Sequence @@ Thread[{, nested /@ Hold[a] // Apply@List}],
    {"]"}}];
nested[x_] := myGrid@{{HoldForm[x]}};

Each argument is spanned by a pink divider:

nested[
 Select[Flatten[Module[{x}, x = #;
      Join[x[[1]], #] & /@ x[[2 ;; -1]]] & /@ igraph, 1], 
  Length@# > 1 &]
 ]

Mathematica graphics

Appendix: ...in a simpler way

It occurred to me that the OP wants the code refactored, which I missed at first.

The most egregious obfuscation is the use of Module to localize the argument #1. It seems the author was not familiar with Function[{x}, body]. One can simply change Module to Function and get rid of the x = #; and the trailing &, preferably adding a comment:

Block[{igraph =
  {{{1, 11}, {2}, {3}}, {{4}, {5, 10}, {6}}, {{7}, {8}, {}}}},
 
 Select[
  Flatten[
   Function[{x}, (* join First list in x to Rest of lists in x *)
     Join[First[x], #] & /@ Rest[x]
     ] /@ igraph, (* for each list in igraph *)
   1],
  Length@# > 1 &]
 
 ]

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

Alternatively, one could name the function and take advantage of Mathematica's pattern-matching and term-rewriting capabilities:

joinFirstToRest[{x1_, x2___}] := Join[x1, #] & /@ {x2}; 

Block[{igraph =
  {{{1, 11}, {2}, {3}}, {{4}, {5, 10}, {6}}, {{7}, {8}, {}}}},
 
 Select[
  Flatten[joinFirstToRest /@ igraph, 1],
  Length[#] > 1 &]
 
 ]

If one is looking for a procedural equivalent to joinFirstToRest /@ igraph, which is the same as Map[joinFirstToRest, igraph] ("I am struggling to write the code without these"), I offer this for educational purposes:

Table[joinFirstToRest[x], {x, igraph}]

(Change Map to Table, pick an iterator x and plug it into the function and the list-iterator form for Table.) The expression inside the OP's Flatten[expr, 1] becomes, after simplifying Function[{x}, body][x] to just body, the following:

Table[Join[x[[1]], #] & /@ x[[2 ;; -1]]], {x, igraph}]

or, transforming Map again,

Table[
 Table[Join[x[[1]], y], {y, x[[2 ;; -1]]}],
 {x, igraph}]

which could be combined into

Table[Join[First@x, y], {x, igraph}, {y, Rest@x}]

The 2D Table form also reveals why the next step might be to Flatten it one level. I usually like Map better than Table, but Table seems easier to read here. I still prefer First@x to First[x] and certainly Rest@x to x[[2 ;; -1]], especially when they are themselves adjacent to brackets and braces.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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