Message Boards Message Boards

0
|
12250 Views
|
38 Replies
|
1 Total Likes
View groups...
Share
Share this post:

Avoiding procedural programming

Posted 3 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 3 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 3 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 3 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 3 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 3 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

The first function shuffleInterval[x_List, n_] takes a List and an another vatiable n, with no constraints but assumed to be Integer(s); which returns a List of Interval(s) and original Integer(s) from x in position order as we are using Map. So the return list shapes as follows (psuedo-code):

{{Interval[x(i) - n, x(i) + n], x(i)},...}

where x(i) is the value based on position on the incoming List. This is why I used Table in my first post for easier understanding. So, on to the next step/function broken down. lappingShuffles[x_List, n_] takes output from shuffleInterval[x_List, n_] as z and accumulates, using Map and a Select function, the x(j,k,l,m,...)(s) and its Interval; where x(i) is a member of that interval. So the return list shapes as follows (psuedo-code):

{{{Interval[x(i) - n, x(i) + n], x(i)}, {Interval[x(j) - n, x(j) + n], x(j)}}, ...}

The next function gatherlappingShuffles[x_List, n_] takes output from lappingShuffles[x_List, n_] as z and takes the second column of each items of z. So the return list shapes as follows, for example (psuedo-code):

{{x(i),x(j)}, x(j), {x(k), x(l), x(m)}, ...}

This is the result which we take the Floor Mean of. However, you are stating that the functions as presented are not gathering or grouping properly, thus the Mean is off or presentation is confusing.

So how to test that gatherlappingShuffles[x_List, n_] is working as designed and as OP requested. To test just call gatherlappingShuffles[x_List, n_]. Say gatherlappingShuffles[myxIntegers, 20] and see what it returns. Then apply/map Floor Mean to each item on the list. Or on a few of those list items do some calculations by hand see what you get.

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

I thought I was being clear that the only reason I split up the functions is for you to better study the process. Each function can be called individually, with the same parameters, and their results can be observed. Just as I did in a previous post NumberLinePlot[shuffleInterval[myIntegers, 10]] to plot.

For example try:

{myxIntegers, 
  myyIntegers} = {BlockRandom[RandomInteger[100, 100], 
   RandomSeeding -> 42], 
  BlockRandom[RandomInteger[100, 100], RandomSeeding -> 44]};
gatherlappingShuffles[myxIntegers, 20]

All the next function does is Map the Floor Mean functions to each item. The above statement assumes that all 4 ...Shuffle(s) functions are defined.

Whether the solution paths provided are functional and/or make use of recursion; I can't truly speak to that. It may be best to clearly state your problem and goals. And see if this community can help you find other functional solutions. I interpreted your request to avoid procedural programming to mean use a functional programing paradigm.

"Functional programming is a programming paradigm in which we try to bind everything in pure mathematical functions style. It is a declarative type of programming style. Its main focus is on 'what to solve' in contrast to an imperative style where the main focus is 'how to solve'. It uses expressions instead of statements. An expression is evaluated to produce a value whereas a statement is executed to assign variables."

But WL provides a good environment for exploration.

So if the Mean is not what you want change it.

Please, note that Dynamic(s) are tricky. My best guess is that you may want to wrap these Dynamic variables and Slider(s) in a DynamicModule.

POSTED BY: Hans Michel
Posted 3 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 3 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 3 years ago

I notice that my head is not optimal tonight, so maybe this is a good time to just briefly teel you all what I'm eventually after :

I am a photographer and graphic artist. The first things I started doing in Mathematica was playing with Random points and lines and then trying to administer some kind of order in the randomness. For this particular little piece of code I had the following in mind : Make a list with n random Xcoordinates Make a list with n random Ycoordinates The two lists will be Transposed to get {point1,point2, . . . point_n} Draw lines between consequtive points. Now thios will give random figures.

The piece of code I asked advice on would unite two coorinates that are <+ delta apart. So bringing a bit of order into the randomness. The bigger I make delta (Slider), the more structure and regularity I will insert into the figure. As I intend to make the thing Dynamic, I can adjust untill I visually like the image and export it for further working on or with. I am trying with different ideas to inject Regularuty or Structure into Randomness.

I hope this 'paints' the picture a bit. I'll post the thing when it's ready.

POSTED BY: B. Cornas
Posted 3 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 3 years ago

I get it, thanks.

POSTED BY: B. Cornas
Posted 3 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 3 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 3 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 3 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 3 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 3 years ago

The speed is not an issue, as the lists will be max 100 numbers. I am baked for today with trying to wrap my head around hans' solution. I'll look into yours tomorrow. But many thanks for your input. To get ideas and solutions from experienced users really opens my eyes (and wears my brain :-)

POSTED BY: B. Cornas
Posted 3 years ago

Paul, I get your solution. The first part is a bit like the solution of Hans, but some shorter.

The ‘Do loop’ I have some problems with understanding.

How can the Flatten function work while the loop is still in progress? As in the second line of the loop :

myint[[p]] = css[[i, 1]]], {i, 1, Length[css]}]; - needs ‘p’, already in the first pass.

I am sure that it’s me who doesn’t see the workings, as I probably think still too much ‘procedural’.

Is there a possibility to step through the loop, to see what happens with each value of I? I mean the way I can do that in debug mode in a procedural language.

To get the final result, the whole procedure should be repeated until there are no more numbers within delta range.

As to my latest idea, to take the mean of the numbers within the delta range :

Make two results, one where the first number gets replaced by the second, and one vice versa. Then take the rounded mean of the numbers in equal positions in the two resulting lists. I have to think still how to do that for taking the mean for 3 or more numbers that lie within the delta range, so that the weight is the same for each number.

Thanks Paul.

POSTED BY: B. Cornas
Posted 3 years ago

In general if I want to see what's going on I put a strategic print statement in, you do have to be cautious in this regard particularly if as a result there are many items to print, it is sometimes wise to also include a Pause[1] after the print so you can interrupt the program. Anyway i made a small alteration to the original program to move the if statement outside of the do loop as shown here.

delta = 10; myint = {11, 28, 66, 36, 94, 8, 44}; Print[myint]; ss = 
 Subsets[myint, {2}]; css = 
 Cases[ss, {a_, b_} /; Abs[a - b] <= delta]; Print[css]; If[
 Length[css] > 0, 
 Do[p = Flatten[Position[myint, css[[i, 2]]]]; 
  myint[[p]] = css[[i, 1]]; Print[myint], {i, 1, Length[css]}]]; myint

To make it so the test is first or second number just change the index in css[[i,2]] to css[[i,1]] and visa versa.

Now in regard to the "mean" version I have re-written the code to hopefully cater for more than 2 terms in the delta range or any number really. It also self adjusts so once a set of numbers have been changed to the mean value, those numbers are not used again even if there is a spanning set of numbers else where, and or if the new mean is also a value in the original list, take a look and see if this is doing what you require.

delta = 10; myint = {79, 90, 67, 56, 54, 43, 8, 90, 2, 71, 17, 64, 58,
   83, 14, 98, 41, 4, 32, 85}; Print[myint]; sd = 
 Sort[myint]; groups = 
 Table[Flatten[{sd[[i]], 
    Select[sd, sd[[i]] < # <= sd[[i]] + delta &]}], {i, 1, 
   Length[sd]}]; Print[
 Flatten /@ 
  Partition[Riffle[groups, Floor /@ Mean /@ groups], 2]]; Do[
 If[Length[Intersection[myint, groups[[i]]]] == Length[groups[[i]]], 
  a = Floor[Mean[groups[[i]]]]; 
  p3 = Sort[
    Flatten[Table[
      Position[myint, groups[[i, r]]], {r, 1, Length[groups[[i]]]}]]];
   myint[[p3]] = a], {i, 1, Length[groups]}]; myint

Alter the initial list and see if it behaves as expected.

Paul.

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 3 years ago

Hi Hans, thanks again for your contribution.

All right, here the bigger number that is within the range gets replaced by the smaller. That is also all right with me.

Your solution is setting the bar quite high for me - which is great, but I need time to really explore your solution bit by bit. And live a lot in the documentation :-)

I found the following :

  1. Outer[List, tt, tt], 1 makes an Array with all the possible 2 number combinations from the original list tt, which are 49 in total (7^2). So that I got.

  2. Cases[#, {x, y} /; x < y] & is a pure function which searches for the pattern x<y The Flatten gives eventually back to t1 an array with the first number < second number. (21 lists left).

  3. t2 = Cases[t1, {x, y} /; 0 < Abs[x - y] <= 10] Here only the lists that comply to the range criterion of 10 are included in t2.

    I think the bigger than zero part (0 < Abs[ ) could be left out, as the lists with equal numbers have already been filtered out.

  4. rr = Rule @@@ (Reverse /@ t2) I see what it does, but do not understand the syntax. Could you explain a bit ?

From the doc : f@@@expr or Apply[f,expr,{1}] replaces heads at level 1 of expr by f. I don’t get this.

I tried to rewrite the line into for me more familiar form ; rr = Apply[Rule[ Map[Reverse], t2]] But this does not work. How could the line be written with Apply[] and map[] ?

  1. tt /. rr This I get. The rules of rr are applied to my original list.

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

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.

Thanks a lot :-)

POSTED BY: B. Cornas

Hello B.,

I think the bigger than zero part (0 < Abs[ ) could be left out, as the lists with equal numbers have >already been filtered out.

you are right.

rr = Rule @@@ (Reverse /@ t2)

I see what it does, but do not understand the syntax. Could you explain a bit ?

Reverse changes the order in the elements of t2 : { a, b } becomes { b, a }

Rule@@@ changes the heads of the elements of t2 . { b, a } becomes b -> a

Written out you should try

rr =Apply[Rule, Map[Reverse, t2], {1}]
t2/.rr

Regards, Hans. If you have more questions please feel free to contact me by mail ( h.dolhaine@gmx.de)

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 3 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 3 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

It is not clear how you want to handle certain cases (for example, does the 11 take precedent over the 8 because it came first? What about the 28, 36, and 44 -- they are within 10 of each other but span more than 10. These details need to be worked out)

One suggestion is to use Differences and Position and then Replace values in your list.

Not a complete answer because I do not understand what you actually want, but you can do:

In[1]:= Sort[myints]

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

and

In[1]:= Differences[Sort[myints]]

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

and

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

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

These positions point to the 8, the 28 and 36 in the sorted list. If you shift them by one, they point to the 11, the 36, and the 44 in the sorted list. You can now write a something to map replacement rules on the original list -- For example, replacing the 8 with 11, 28 with 36, or vice versa.

Hope this helps.

Regards

POSTED BY: Neil Singer
Posted 3 years ago

Instead of giving you code, I'll give you one idea how you might try to think about this functionally.

You have to write a function. One way might be to create a function that takes two arguments, the list of items processed thus far and the list of items not yet processed.

All functional programs need a test to tell if they are finished. In this function it is finished if the second argument is empty and in that case it just returns the first argument.

If it is not finished then it takes the first item from the unprocessed list, perhaps uses the Mathematica function Nearest to test whether that item is close enough or not, and calculates the next item to append to the processed list.

Can you convince yourself that this modification process of the next item in the unprocessed list does not somehow corrupt the definition of the problem? That might or might not be exactly true. Perhaps try thinking of some really strange cases that might make this behave oddly.

Then the function calls itself with the new longer processed list and the new shorter unprocessed list.

Can you figure out what the thinking process was to get there? That is the most important step, much more important than what the answer is.

Can you convince yourself that this exactly correctly implements your description? And that your description is exactly correct?

Could you then start thinking if there might be any other way to implement this functionally?

POSTED BY: Bill Nelson

I think your problem is not uniquely to be solved - or I do not understand what you want.

Something like this? Neither gives the answer you asked for, but numbers fulfilling your criterion are substituted.

tt = {11, 28, 66, 36, 94, 8, 44}
tt /. (Rule[#[[1]], #[[2]]] & /@ 
   Select[Flatten[Outer[List, tt, tt], 1], And[0 <= Abs[#[[1]] - #[[2]]] <= 10, #[[1]] < #[[2]]] &])

or

tt /. (Rule[#[[1]], #[[2]]] & /@ 
   Select[Flatten[Outer[List, tt, tt], 1],  And[0 <= Abs[#[[1]] - #[[2]]] <= 10, #[[1]] > #[[2]]] &])
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

Group Abstract Group Abstract