Group Abstract Group Abstract

Message Boards Message Boards

0
|
14.9K Views
|
38 Replies
|
1 Total Like
View groups...
Share
Share this post:

Avoiding procedural programming

Posted 4 years ago

I am very new to Mathematica and have to rethink my 'procedural' ways of programming. That is not always easy. I am making progress, but here I have no clue, besides going down the 'repeat and if' rabbit hole.

I create a list of random integers. I have a Dynamic Slider to adjust delta (between 0 and 20). Let's say the Slider is adjusted to value 10.

Now I want all the integers in the list that are 10 or less apart, to become the same integer.

E.g. myIntegers = {11,28,66,36,94,8,44}

After the 'treatment' the list should be : {11,28,66,28,94,11,44} The 36 is within 10 from 28 and the 8 is also within 10 from 11, so in both cases the integer within the delta range gets to be the value of the first (36 becomes 28).

How could I go about this problem in a functional or symbolic way?

POSTED BY: B. Cornas
38 Replies
Posted 4 years ago

Here is the Dynamic result I made from your solutions. I applied the solution of Hans Michel, but I will make versions with the other solutions as well, just to learn. Thanks again to all of you :-)

Attached the nb with my latest version.

Beat

Attachments:
POSTED BY: B. Cornas
Posted 4 years ago

There is a snag I've ran into already a couple of times and so I do here.

When I make a variable that gets it's value (here a List) from a Dynamic[ xxxx code xxxxx], then I cannot work with that variable anymore.
E.g.

resizeFactor = 0.8;
Row[{Slider[Dynamic[resizeFactor], {0.1, 2}]}]

ptsSeedX = Table[RandomInteger[100], numLinesMax];

(*   make scaled copies and displace them  *)

resize1X =   Dynamic[Round[Times[ptsSeedX, resizeFactor]]]

offsetX = RandomInteger[{-50, 50}]   (* A  random OffsetX  *)

 (*   BOTH LINES BELOW DO NOT WORK   *)

displace1X = resize1X + offsetX   
displace1X ={ resize1X} + offsetX

I get something in the form of : 20+{24,23,47,11} being the OffsetX + the List "resize1X"

I suspect (also from other situations) that the Dynamic causes the non-functioning. How can I keep the Dynamic and still get the last line working?

POSTED BY: B. Cornas
Posted 4 years ago

This is what I have so far, based on the latest version of Hans Michel.

Clear[lappingMeanShuffles, gatherlappingShuffles, lappingShuffles, 
  shuffleInterval, myxIntegers, myyIntegers];

numlines = 20;          (*  This has to be made adjustable with a Slider  *)
myxIntegers = Table[RandomInteger[100], numlines];
myyIntegers = Table[RandomInteger[100], numlines];

(*myxIntegers ={4,8,7,8}
myyIntegers ={4,8,7,8}*)

(*   FUNCTIONS    *)

shuffleInterval[x_List, n_] := 
  Module[{}, Map[({Interval[{# - n, # + n}], #}) &, x]];
lappingShuffles[x_List, n_] := 
  Module[{z = shuffleInterval[x, n]}, 
   Map[Function[y, Select[z, IntervalMemberQ[#[[1]], y] &]], x]];

(*  OF  lappingShuffles[x_List,n_]:=Module[{z=shuffleInterval[x,n]},\
Map[Function[y,Select[z,Between[y,#[[1]]]&]],x]];  *)

gatherlappingShuffles[x_List, n_] := 
  Module[{z = lappingShuffles[x, n]}, Map[(#[[All, 2]]) &, z]];
lappingMeanShuffles[x_List, n_] := 
  Module[{z = gatherlappingShuffles[x, n]}, Map[Floor[Mean[#]] &, z]];


Manipulate[
 Graphics[
  Map[Line[#] &, 
   Partition[
    Transpose[{lappingMeanShuffles[myxIntegers, n], 
      lappingMeanShuffles[myyIntegers, a]}], 2, 1]], 
  ImageSize -> 600], {{n, 20, "Delta X"}, 0, 100, 1, 
  Appearance -> "Labeled"}, {{a, 20, "Delta Y"}, 0, 100, 1, 
  Appearance -> "Labeled"}]
POSTED BY: B. Cornas

See if the following helps:

Clear[lappingMeanShuffles, gatherlappingShuffles, lappingShuffles, shuffleInterval, myxIntegers, myyIntegers];

myxIntegers = {11, 28, 66, 36, 94, 8, 44};
myyIntegers = {41, 13, 82, 26, 43, 74, 46};

shuffleInterval[x_List, n_] := Module[{}, Map[({Interval[{# - n, # + n}], #}) &, x]];
lappingShuffles[x_List, n_] := Module[{z = shuffleInterval[x, n]}, Map[Function[y, Select[z, IntervalMemberQ[#[[1]], y] &]], x]];
gatherlappingShuffles[x_List, n_] := Module[{z = lappingShuffles[x, n]}, Map[(#[[All, 2]]) &, z]];
lappingMeanShuffles[x_List, n_] := Module[{z = gatherlappingShuffles[x, n]}, Map[Floor[Mean[#]] &, z]];
Manipulate[Graphics[Map[Line[#] &, Partition[Transpose[{lappingMeanShuffles[myxIntegers, n], lappingMeanShuffles[myyIntegers, a]}], 2, 1]]], {n, 0, 20, 1}, {a, 0, 20, 1}]

With these parameters (n = 20, a = 14) and the myx..., myy... points we get the resulting image. enter image description here

If you don't wish to deal with Interval :

(* shuffleInterval[x_List, n_] :=  Module[{}, Map[({{# - n, # + n}, #})&, x] ]; 
 lappingShuffles[x_List, n_] := Module[{z = shuffleInterval[x, n]}, Map[Function[y, Select[z, Between[y ,#[[1]] ]&] ], x]]; *)

The functions were broken up to make it easier to follow the code but it can be written back into just one function:

concatShuffle[x_List, n_] := 
  Module[{}, 
   Map[Floor[Mean[#]] &, 
    Map[(#[[All, 2]]) &, 
     Map[Function[y, 
       Select[Map[({Interval[{# - n, # + n}], #}) &, x], 
        IntervalMemberQ[#[[1]], y] &]], x]] ] ];
concatShuffle[{11, 28, 66, 36, 94, 8, 44}, 10]
(* {9, 32, 66, 36, 94, 9, 40} *)

` Thanks

POSTED BY: Hans Michel
Posted 4 years ago

Hans, your manipulate seems to work fine and is what I had in mind. I adapted the script somewhat, so I generate Random x-coordinates and Randon y-coordinates from 0 - 100. That means I also adatpted the two delta's (here n and a to cover the range from 0 to 80). The results are what I expected and are promising. Nice :-)

Tomorrow I will dig deeper ionto your code to really undestand what you have done. I also will make a Slider to control the amount of points (how long the lists for x & y will be). And some more little extra's. It's great to see how a simple problem can be solved in many different ways. I wish I had started earlier with Mathematica :-)

Thanks Hans, it's really appreciated.

POSTED BY: B. Cornas
Posted 4 years ago

Hi Hans, It's a tough cockie that you baked for me :-) Tough in the sense that I cannot yet get my fingers behind it. I'll need more time to explore you're code.

Still, I played around with the Manipulate and added some little things to see the workings better. E.g. I make the original lists for the x- and y- coordinates by using RandomIntegers. Also I included a definite ImageSize, so the graphis does not jump so much when adjusting the sliders.

One thing that I noticed, that when there are 3 or more integers within the Delta range of each other, you dot not get exactly the mean of all of them, but I guess a mean from first the numbers #1 and #2, then that mean is put together with #3 and the new mean is taken, etc. That comes down that later numbers have a bigger weight in the mean. I am not totally sure, as as I cannot see that in the code, but it's an inference from the results.

Also I am in the process of rewriting the code without the Manipulate, but with Dynamic Sliders and other Dynamic controls. I think that gives me a bit more flexibility in the end. But I have not succeeded as yet, mainly because I do not understand the functions in your code all that well. I will study on it more. best, Beat

POSTED BY: B. Cornas
POSTED BY: Hans Michel
Posted 4 years ago

Thanks Hans,

Your detailed explanation certainly helps a lot. I get the the concept and some parts. I need to do more work to figure out the details, something that takes some time, so it might be a couple of days untill I get back to you.

What are the rules you have in mind for the weights, if any? Otherwise, I thought I was faithfuly interpreting your request.

You definitely are. It is that along the way I am changinging my course a little bit. I started out with a vague idea for bringing some order into random connected points. I had no real idea how it would look, just a vague notion. Then along the way, it occured to me that the mean between numbners within the delta range might do a better job. In contrast to what a lot of programmers do or have to do, is my goal at the beginning not very substantiated, but can adapt as I go along.

Functional vs. Procedural programming styles : I think what you write about functional programming is quite enlightning for me. I use the term without a precise understanding what it exactly is, nor how to best apply it. I know procedural programming, but I thought it might be nice to do my things in WL in a Non procedural way as much as possible, just to learn the new and other way of thinking. Otherwise I might stay stuck in my old pardigm :-)

In the next days I will study your kind explanation as good as I can and get back to you. In the meantime, thanks a million Hans, for your help.

Beat

POSTED BY: B. Cornas
Posted 4 years ago

Hans, I've spent some hours this afternoon on your solutions and the sun is starting to come up :-)

I can follow the code (thanks also to your breaking it down into seperate functions) all through and I get the purpose and it's workings. There are some minor details in the syntax that have not yet been completely defrosted for me, but it will come. I am most gratefull for your time and effort.

I think I will use Round[] in stead of Floor[], but is jus a minor detail.

I will start to try to make your code into a Dynamic setup. I will study your suggesion to use DynamicModule. I have already made some things with Dynamic controls, but not everything is clear yet (see my previous post).

I realize that there are very basic things that I am still unaware of. It took me f.i an hour to get the Mean[[{3,4,5},{7,9}}. It does not work like this, but by exploring how you did it, I managed after a while. So I know that I am not comfortable yet with some very basic things, but it will come.

Thanks again, Hans, for your patience.

Beat

POSTED BY: B. Cornas
Posted 4 years ago
POSTED BY: B. Cornas
Posted 4 years ago

Thanks Hans, I'll will study your input tomorrow.

POSTED BY: B. Cornas

B. Cornas

The following is a bit more functional (no more Table(s) etc)

 Clear[lappingMeanShuffles, gatherlappingShuffles, lappingShuffles, 
      shuffleInterval, myIntegers];
    myIntegers = {11, 28, 66, 36, 94, 8, 44};
    shuffleInterval[x_List, n_] :=  
      Module[{}, Map[({Interval[{# - n, # + n}], #}) &, x] ];
    lappingShuffles[x_List, n_] := 
      Module[{z = shuffleInterval[x, n]}, 
       Map[Function[y, Select[z, IntervalMemberQ[#[[1]], y] &] ], x]];
    gatherlappingShuffles[x_List, n_] := 
      Module[{z = lappingShuffles[x, n]}, Map[(#[[All, 2]]) &, z]];
    lappingMeanShuffles[x_List, n_] := 
      Module[{z = gatherlappingShuffles[x, n]}, Map[Floor[Mean[#]] &, z]];
    lappingMeanShuffles[myIntegers, 10]
(* {9, 32, 66, 36, 94, 9, 40} *)

Splitting it up into step like functions still allows for

Manipulate[lappingMeanShuffles[myIntegers, n], {n, 0, 20, 1}]

and visualizations of the overlaps

NumberLinePlot[shuffleInterval[myIntegers, 10]]
POSTED BY: Hans Michel

To make things easier to apply, I made a function called scrubber that takes one argument, named x, that must be a list. I could have named it anything. Inside the function, it puts that input list wherever I use “x”.

The module function is a way to do a sequence of commands and make variables like pos and sorted local variables to the module.

I hope that helps.

POSTED BY: Neil Singer
Posted 4 years ago

I get it, thanks.

POSTED BY: B. Cornas
Posted 4 years ago

For me takes time to study all your very welcome inputs, and that is the reason that my replys are slow :-) But be sure that I'll study all of them.

POSTED BY: B. Cornas

With new rule of use the Mean.

Clear[lappingShuffles, lappingMeanShuffles, myIntegers];
myIntegers = {11, 28, 66, 36, 94, 8, 44};
lappingMeanShuffles[x_List, n_] := Module[{}, 
   Table[Floor[Mean[
         Table[
           Select[
            Table[{x[[i]], Interval[{x[[i]] - n, x[[i]] + n}], i},
                  {i, Length[x]}]
                , IntervalMemberQ[#[[2]], x[[j]] ] &],
                {j, Length[x]}][[l]][[All, 1]] 
      ]
     ], {l, Length[x]} ]
   ];

lappingMeanShuffles[myIntegers, 10]
(* {9, 32, 66, 36, 94, 9, 40} *)

Manipulate[lappingMeanShuffles[myIntegers, n], {n, 0, 20, 1}]
POSTED BY: Hans Michel
Posted 4 years ago

Hi Neil, As you indicated, I had not clearly defined my problem. For me it was not so important whether the bigger number got repacked by the smaller or vice versa. Now I think it would be nice to take the mean of the two. This would also resolve the problem I had not noticed in my example list of integers.

{11, 28, 66, 36, 94, 8, 44}

You had rightly noticed that there are three numbers within the 10 range : 28,36,44. So to resolve situations like this, and anyhow, it might be best to take the rounded mean for the numbers that are within the defined range of 10. So eventually the list would become {9 , 36 ,66, 36 , 94 , 9 , 36}

I can follow your approach,Neil,and I like the seemingly 'Wrong' move away from the solution (the sorting), only to come back strong further on.

I just notice in your last post, that you have solved the ’28,36,44’ problem as well. Here letting the smallest number prevail.

I can tag along your solution (although I would not have been able yet to come up with it), just the following line is still unclear to me :

scrubber[x_List] := Module[{pos, sorted}, sorted = Sort[x];

Is [xList] the same as [x] but for Lists?

The part after the := I don’t get. What is ‘x’, f.i.?

Thanks, Neil

POSTED BY: B. Cornas

B. Cornas:

Try the following:

Clear[lappingShuffles, myIntegers];
myIntegers = {11, 28, 66, 36, 94, 8, 44};
lappingShuffles[x_List, n_] := Module[{},
  Map[First[#[[1]]] &,
   Table[MinimalBy[
     Table[Select[
        Table[{x[[i]], Interval[{x[[i]] - n, x[[i]] + n}] , i}, {i, 
          Length[x]}],
        IntervalMemberQ[#[[2]], x[[j]]] & ], {j, Length[x]}][[k]],
     Last ], {k, Length[x]}]
   ]
  ];
lappingShuffles[myIntegers, 10]
(* {11, 28, 66, 28, 94, 11, 36} *)

Manipulate[lappingShuffles[myIntegers, n], {n, 0, 20, 1}]

Some refactoring may still be needed. But this is what I can quickly post. Also may need further code changes depending on what the final ruling is on the last entry on the list is it 44 or 36?

POSTED BY: Hans Michel
Posted 4 years ago

Hans, this looks very neat. I like the Slider, so I can control the amount of replacement of the numbers <= delta. That plays into what I want. Tonight I feel I am too tired to understand what you really did, but it sure seems very nice. I will dive into it as soon as I can. Thanks.

POSTED BY: B. Cornas

If you just want to replace the higher values with the lower values, I think this does the trick.

scrubber[x_List] := 
Module[{pos, sorted}, sorted = Sort[x]; 
pos = Position[Differences[Sort[myints]], n_ /; 0 < n <= 10]; 
x /. MapThread[
Rule[#1, #2] &, {Extract[sorted, pos + 1], Extract[sorted, pos]}]]

myints = {11, 28, 66, 36, 94, 8, 44}

In[20]:= FixedPoint[scrubber, myints]

Out[20]= {8, 28, 66, 28, 94, 8, 28}
POSTED BY: Neil Singer

Here is again a different approach. Define a function, which finds for each element in a list the preceeding elements with a difference <= 10 and additionally their positions in the list. As there may be more than one the result is given as

{ Position of element, element ee, { e1, e2, ...} }

with Abs [ ee - ei ] <= 10.

(In the example we have always only one ei )

Then it is possible to replace ee by one of the ei's.

Clear[fF];
fF[x_, tT_] := Module[{},
  pp = Position[tT, x][[1, 1]];
  If[pp == 1, Return[0]];
  tH = Take[tT, pp - 1];
  aL = Select[tH, Abs[# - x] <= 10 &];
  res = If[aL =!= {}, {pp, x, aL}, 0];
  res
  ]

tt = {11, 28, 66, 36, 94, 8, 44}
res1 = DeleteCases[fF[#, tt] & /@ tt, 0]
res2 = {#[[1]] -> #[[3, 1]]} & /@ res1 // Flatten
tt = ReplacePart[tt, res2]

But this still does not give what you want, because the last 44 is replaced by 36.

POSTED BY: Hans Dolhaine
Posted 4 years ago

Hans, I get the idea and see that it works. I also can sort of tag along, but I need to spend some more time on the details of the actual syntax. For me this ia mostly a way of learning to think differently and to get the sometimes quite cocise syntax. In my procedural programming, the syntax is more spread out and less compressed. This new way is challenging but also great fun. I just need to make the =miles, but I'll get there :-)

Thanks.

POSTED BY: B. Cornas

Sorry, wrong click.

POSTED BY: Hans Dolhaine
Posted 4 years ago

Maybe a few more ideas here, I have made a slight alteration to the original list to give a more varied outcome. The code wouldn't be very efficient for large lists or particularly fast, anyway here it is.

delta = 10; myint = {11, 35, 28, 66, 36, 94, 8, 44}


ss = Subsets[myint, {2}]


css = Cases[ss, {a_, b_} /; Abs[a - b] <= delta]


Do[If[Length[css] > 0, p = Flatten[Position[myint, css[[i, 2]]]]; 
  myint[[p]] = css[[i, 1]]], {i, 1, Length[css]}]; myint
POSTED BY: Paul Cleary
Posted 4 years ago
POSTED BY: B. Cornas
Posted 4 years ago
POSTED BY: B. Cornas
Posted 4 years ago
POSTED BY: Paul Cleary

Another approach, still not giving exactly what you want, but your conditions are fulfilled

tt = {11, 28, 66, 36, 94, 8, 44}

newt[t_] := Module[{},
  t1 = Flatten[Cases[#, {x_, y_} /; x < y] & /@ Outer[List, tt, tt], 
    1];
  t2 = Cases[t1, {x_, y_} /; 0 < Abs[x - y] <= 10];
  rr = Rule @@@ (Reverse /@ t2);
  tt /. rr
  ]

FixedPoint[newt, tt]

(*  {8, 28, 66, 28, 94, 8, 36}  *)
POSTED BY: Hans Dolhaine
Posted 4 years ago
POSTED BY: B. Cornas
POSTED BY: Hans Dolhaine

I understand FixedPoint. But why does FixedPoint not continue and also replace ’36’ with ’28’? The >rule 36->28 is present in rr.

In fact the fixedpoint is not necessary. One has to provide that rr is applied until there is no more change.

tt = {11, 28, 66, 36, 94, 8, 44}

newt[t_] := 
 Module[{}, 
  t1 = Flatten[Cases[#, {x_, y_} /; x < y] & /@ Outer[List, tt, tt], 
    1];
  t2 = Cases[t1, {x_, y_} /; 0 < Abs[x - y] <= 10];
  rr = Rule @@@ (Reverse /@ t2);
  tt //. rr]

newt[tt]

I also don’t get the very beginning :

newt[t_] := Module[{}, I guess the Module just protection and not really essential. But what is the {} >just after.

hmmm. I use Module to write longer subprograms. The {} encloses variables (here none) which are local to the Module and not visible in main.

POSTED BY: Hans Dolhaine

The idea was to sort the list, establish replacement rules and apply that to the *original * list in order.

I’m traveling now but I’ll post an example later.

Regards

POSTED BY: Neil Singer
Posted 4 years ago

Neil, I understand your idea. I had been thinking of sorting the list, to make things easier. Unfortunately, I need (at least in the end) , the order to be like it was in the first place, but with the adapted numbers. But the original order needs to be preserved.

Still 'Position[ ]' might be a valuable tip

POSTED BY: B. Cornas

This is what I had in mind. Obviously you need to decide what should be replaced:

In[5]:= sorted = Sort[myints]

Out[5]= {8, 11, 28, 36, 44, 66, 94}

In[6]:= difs = Differences[Sort[myints]]

Out[6]= {3, 17, 8, 8, 22, 28}

In[7]:= pos = Position[Differences[Sort[myints]], n_ /; n <= 10]

Out[7]= {{1}, {3}, {4}}

In[8]:= rules = 
 MapThread[
  Rule[#1, #2] &, {Extract[sorted, pos], Extract[sorted, pos + 1]}]

Out[8]= {8 -> 11, 28 -> 36, 36 -> 44}

In[9]:= myints

Out[9]= {11, 28, 66, 36, 94, 8, 44}

In[10]:= myints /. rules

Out[10]= {11, 36, 66, 44, 94, 11, 44}
POSTED BY: Neil Singer
Posted 4 years ago

With these answers I certainly can move on. Thanks. Hans : I think your second example works, but I really need to study it to get it. It's more compact than the code I write at my current level of Mathematica.

I certainly appreciate the answer of Bill Nelson, as it gives me a direction in which way to think. This is exactly what I need, a new way to think about solutions. GREAT :-)

Neil : I agree. I should have been clearer in my question. I took the first number and adapted the next one within the delta range to become as the first. I could have taken the second or the mean. And my example, I noticed is indeed a bit double, in that 44 is also within the range of 36, which in its turn is within the range of 28. I have to rethink how I want that to be solved.

But for now, I will take time to study the answeres and play with them. Thanks agian, this really helps my understanding of this wonderfull new language and way of thinking. I'll get back after working with the new ideas.

Best, Beat

POSTED BY: B. Cornas
POSTED BY: Neil Singer
Posted 4 years ago
POSTED BY: Bill Nelson
POSTED BY: Hans Dolhaine
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard