11 Replies Latest reply on Sep 14, 2012 11:03 AM by dgolberg

    Select X# of variables from array at the furthest possible intervals.

    dgolberg Level 1

      Ok, I've been working on this one for a while and I'm thinking I'm either missing something really stupidly simply because of it, or I've got my equation wrong still. 

       

      Basically, what I'm trying to do is select X number of items out of an array.  The only catch is, these items need to be as far apart from each other as possible.  So for example, one time I might have an array with 93 items in it which I need to grab 36 of them, evenly spaced through the array (so the first one would be the first one in the array, and the last one would be the last in the array.

       

      How would I go about telling the script to grab the correct array values (the most evenly spaced ones), ending up with only the X amount of output values?

       

      Thanks!

      dgolberg

        • 1. Re: Select X# of variables from array at the furthest possible intervals.
          c.pfaffenbichler Level 9

          Does this help?

          var number1 = 93;
          var number2 = 36;
          var theFraction = number1 / (number2 - 1);
          var theArray = new Array;
          for (var m = 0; m < number2 + 1; m++) {
          theArray.push(Math.round(theFraction * m))
          };
          alert (theArray.join("\n"));
          

           

          Edited: Sorry, I had made a mistake and corrected the line

          var theFraction = number1 / (number2 - 1);

          1 person found this helpful
          • 2. Re: Select X# of variables from array at the furthest possible intervals.
            dgolberg Level 1

            That does work, but I believe I may have forgot something in my description.  I'm currently cycling through an array of values to find matches to a set of ranges.  It's finding the matches fine, but I need to somehow tell it to select one, then skip so many matches before picking another so that the "chosen" matches are as evenly spaced as possible.  How would I go about doing it that way so that the array length can be changed regardless?  I still need to do something else with the other matches, but these X number (36 in the example) are the more important ones.  Any ideas how to handle that?

             

            Edit: I'm basically marking the ones furthest from eachother as masters, and the rest are considered duplicates or "slaves" of the master they're closest to matching.

            • 3. Re: Select X# of variables from array at the furthest possible intervals.
              c.pfaffenbichler Level 9

              It's finding the matches fine, but I need to somehow tell it to select one, then skip so many matches before picking another so that the "chosen" matches are as evenly spaced as possible. 

              Sorry, I don’t quite follow.

              Could you give an example?

               

              The result (theArray) could be used as the indices for the Master-elements – does that not suffice?

              • 4. Re: Select X# of variables from array at the furthest possible intervals.
                c.pfaffenbichler Level 9

                If you are talking aboud Layers for example does this work? (To keep it simple I just used the top level layers of a document.)

                // 2012, use it at your own risk;

                #target photoshop

                if (app.documents.length > 0) {

                var myDocument = app.activeDocument;

                var theArray = myDocument.layers;

                var number1 = theArray.length - 1;

                var number2 = 6;

                var theFraction = number1 / (number2 - 1);

                var theMasters = new Array;

                var theIndices = new Array;

                for (var m = 0; m < number2; m++) {

                theMasters.push(theArray[Math.round(theFraction * m)])

                };

                alert (theMasters.join("\n"));

                };

                • 5. Re: Select X# of variables from array at the furthest possible intervals.
                  dgolberg Level 1

                  Hmm, this is kind of a different perspective than what I was originally thinking, but it might work.  I'll have to test it out, though it would require me running the array twice; the first time picking out the specific ones and splicing them out of the array, the second simply grabbing the remainder.

                   

                  To put it a little differently, what I was originally thinking is cycling through an array (this array's length and content varries depending on the input), and would grab the the "masters" out of the array at the set intervals (these intervals are where I'm having the most trouble), and anything it finds matching a set range for the current loop cycle that isn't considered a "master" is placed under the master as a "slave" (or essentially, a duplicate).  Below is an example of one of the loops I'm using (I have 3 nested loops in order to cycle through 3 "dimensions" of values) with my last attempt at this issue (which is only correct in certain ranges rather than all ranges like I need).

                   

                  var DF = tA.length / mNum;  //tA.length is the array length, mNum is the number of masters desired from that array.  For example, array length of 100, mNum of 75; DF = 1.333333....
                  var master = 0;
                  
                  for(var z=range[1];z<range[2]+2;z=z+5) { //Cycles through the array 5 units at a time (to speed up the script)... There are 2 other loops above this using the y and z variables seen in the if statements below.
                       for(var i=0;i<tA.length;i++) { //Cycles through the tempArray to find matches to the current cycle of the above loops, +/- 2
                             if(tA[i][0] <= x + 2 && tA[i][0] >= x - 2 && tA[i][1] <= y + 2 && tA[i][1] >= y - 2 &&tA[i][2] <= z + 2 && tA[i][2] >= z - 2 && master < 1) { //Checks for a match, and if the master is less than 1, it sets the match as a master.
                                 master = master + DF; //Adds the DF (short for Dupe Frequency) to the current master number.
                                 outArray.push(tA[i]); //Set the match as a master
                            } else if(tA[i][0] <= x + 2 && tA[i][0] >= x - 2 && tA[i][1] <= y + 2 && tA[i][1] >= y - 2 &&tA[i][2] <= z + 2 && tA[i][2] >= z - 2 && master >= 1) { //Checks for a match, and if the master is greater than 1, it sets a duplicate.
                                 master = master - 1;
                                 outArray[outArray.length-1].push(tA[i][3]); //Set the match's name as a slave under the last master
                            }
                       }
                  }
                  

                   

                  Basically, using the code above; I need it to somehow (while cycling through the tA.length loop), figure out how often it should grab either a slave or a master (depending on which there are more of), and then the next X number of matches are either a master or a slave (again, depending on which there are more of).  So, for example, if there are 25 masters, out of 100 total items in the array, it would pick one master, the next 3 matches would be slaves, and then it would pick another master, 3 more slaves, etc. etc.  Where things start getting out of whack is when the intervals start ending up in fractions (say every 1.5 is a slave).  Obviously, you can't grab half of one, so you'd need to do a pattern more like: 1 master, 1 slave, 1 master, 2 slaves, 1 master, 1 slave; etc.

                   

                  The part I'm having trouble with is getting a working equation that knows how often to pick the (in the example above) slaves based on this varying pattern, and do so accurately regardless of the array length to master/slave ratio (the above method seems to get further off as the mNum gets closer to the tA.length).

                   

                  I guess, more than anything really, I'm just having trouble getting the math to work out right as I'm apparently using the wrong equation in my code.  If anyone has any ideas though, let me know.

                  • 6. Re: Select X# of variables from array at the furthest possible intervals.
                    c.pfaffenbichler Level 9

                    Could you please post an example of an original (short) array, the numbers you use and the results you want to achieve?

                    • 7. Re: Select X# of variables from array at the furthest possible intervals.
                      dgolberg Level 1

                      An example array might be something like the following:

                       

                      var tA = []; //Note: These are not in order as they won't always be grabbed in order from their source (an external CSV file typically); hence the need for the multiple loops to order them as best as possible.
                      tA[0] = new Array(1,12,43,"Set 4");     //mNum = 4 First Master
                      tA[1] = new Array(34,26,86,"Set 5");
                      tA[2] = new Array(87,45,82,"Set 2");
                      tA[3] = new Array(93,45,43,"Set 1");     //mNum = 4 Fourth Master
                      tA[4] = new Array(16,23,65,"Set 7");
                      tA[5] = new Array(74,34,53,"Set 9");
                      tA[6] = new Array(73,45,41,"Set 10");     //mNum = 4 Third Master
                      tA[7] = new Array(18,58,75,"Set 3");
                      tA[8] = new Array(34,28,29,"Set 6");     //mNum = 4 Second Master
                      tA[9] = new Array(69,31,17,"Set 8");
                      

                       

                      The desired result if mNum = 4 would be array numbers 0, 8, 6, and 3 (in that order) as masters, with 4 and 7 being a slave of [0] aka "Set 4" (end result would be the nested array of Array(1,12,43,"Set 4","Set 7","Set3"); in the output array); 1 and 9 a slave of [8] "Set 6"; and 5 and 2 being a slave of [6] "Set 10"; and in this case, "Set 1" (the 4th master) would not have a slave since the closest number is not x/y/z -2 or greater and it's the last item selected.  In other words, the output array would look like this:

                       

                      var oA = [];  //The output array as generated by the script.
                      oA[0][1,12,43,"Set 4","Set 7","Set3"];
                      oA[1][34,28,29,"Set 6","Set 5","Set 8"];
                      oA[2][73,45,41,"Set 10","Set 9","Set 2"];
                      oA[3][93,45,43,"Set 1"];
                      

                       

                      Of course, I have a LOT more in an array than this, and the numbers are generally closer together, but this gives a general idea.

                       

                      The loops basically work like a clock; the 3rd number/loop (z) getting checked every 5 from 0-100 before the second number/loop (y) goes up a cycle, of which that would cycle 0-100 before the first number/loop (x) would go up a cycle (so the z loop is nested in the y loop which is nested in the x loop).  Inside these 3 loops, the tA loops each z loop cycle to check the x/y/z +/- 2 to see if there is a match (sometimes there might be more than 1), and sets it appropriately as a master or slave based on the equation.  Each time a master or slave is found, a ticker would have to be adjusted via this equation to tell the script what the next match is going to be; either a master or a slave.  I hope that makes sense.

                      • 8. Re: Select X# of variables from array at the furthest possible intervals.
                        c.pfaffenbichler Level 9

                        Quite frankly your approach seems so convoluted to me that I don’t follow.

                        Including the Strings seems just confusing to me in this context, while it may be necessary for ultimate goal. Could you explain with just the indices?

                         

                        Why are 4 and 7 slaves of 0?

                        Why should 0 come before 8,6,3 but those be ranking the other way?

                        • 9. Re: Select X# of variables from array at the furthest possible intervals.
                          dgolberg Level 1

                          0, 8, 6, and 3 would be the masters, because that is the order the loops would find them in (and actually, I did make a mistake in that... it should actually be 0, 1, 6, and 3) .  If you order them from smallest to greatest based on how the nested loops work, the order would be:

                           

                          tA[0] = new Array(1,12,43,"Set 4")     1st
                          tA[0] = new Array(16,23,65,"Set 7")
                          tA[7] = new Array(18,58,75,"Set 3")
                          tA[1] = new Array(34,26,86,"Set 5")     2nd
                          tA[8] = new Array(34,28,29,"Set 6")
                          tA[9] = new Array(69,31,17,"Set 8")
                          tA[6] = new Array(73,45,41,"Set 10")     3rd
                          tA[5] = new Array(74,34,53,"Set 9")
                          tA[2] = new Array(87,45,82,"Set 2")
                          tA[3] = new Array(93,45,43,"Set 1")     4th
                          

                           

                          The string is just basically the item's name.  Since we store all the data for all the items in the original file, we only need the name when declaring one as a slave/duplicate in the new output file, but for the masters, we want all the data so it can go straight into use without having to check another file for its data.  So basically, we're trying to make lists of varying sizes while each item is as unique as possible.

                           

                          I guess the best way to look at it would be to think of the 3 values as part of a color scale such as LAB or HSB.  The string would be like the name of the color.  Obviously, some of the colors might be really close, so they might not be easy to tell the difference between.  In other cases, there may simply be too many for a specific list size, but we'd still want the most unique ones possible from the main list when making the new list.

                          • 10. Re: Select X# of variables from array at the furthest possible intervals.
                            c.pfaffenbichler Level 9

                            Sometimes a concrete example helps – in this case it doesn’t help me; though others may see it clearer.

                            Also you have two in the list, so something may be amiss.

                             

                            Can you please provide an example purely with the indices and no further information?

                            So when you have Array-items 0 through 12 (or 9 or whatever), what is the resulting array supposed to look like?

                            • 11. Re: Select X# of variables from array at the furthest possible intervals.
                              dgolberg Level 1

                              I actually just solved the issue.  I had actually had the equation I was looking for a while back, but I had thought I needed to split it into 2 depending if there were more masters or more slaves, but just found out it only needed the one equation to make it work.  It's not 100% accurate, but it's at least 95-99% accurate, which is well within acceptable ranges for what we're doing with it.  Anyway, below is an example of the code used with the correct equation:

                               

                              function getMasters(tA,mN,cA) { //tA is the temp array, mN the number of masters, and cA is the column array (tells the script what column of a CSV file to look in for appropriate data).
                                   outArray = [];
                                   var ttl = tA.length;
                              
                                   var dupes = ttl - mN;
                                   var DF = mN / dupes; //The equation I was looking for.  Still is occasionally off by 1-2 masters, but within acceptable ranges as output does not have to be 100% exact, just close.
                              
                                   var start = 1; //Makes sure the first item is selected as a master
                              
                                   for(var z=value1[5];z<value1[6]+3;z=z+5) {
                                       for(var i=0;i<tA.length;i++) {
                                          if(match && start >= 1) { //match is if the items in the array match the target range (figured it's not as important as the part I was actually looking for).
                                              start = start - 1; //Subtracts 1 from start to determine if the next match is master or slave.
                                              outArray.push(tA[i]); //Add to the outArray as a master
                                          } else if(match && start < 1) {
                                              start = start + DF; //Adds DF to start to determine if the next match is a master or slave (if it is 1 or greater, it's a master)
                                              var c = outArray.length-1; //Get the last master of the outArray
                                              outArray[c].push(tA[i][cA[3]]); //Add the match's name to the end of the row on the last master (signifies a duplicate)
                                          }
                                      }
                                  }
                              }
                              

                               

                              Anyway, the reason for the if statements is to put the otherwise randomly loaded items in the array into a relatively numerical order.  A list of 1500 items takes approximately 10-30 seconds to run depending on the desired number of masters.  Far faster than doing it manually, lol.

                               

                              I'm thinking of eventually adding a while loop to loop through the outArray and create/remove more masters if the length doesn't match the desired number of masters, but that will have to wait for now as more important matters now take precedence.

                               

                              Anyway, thank you for your attempts to assist me with this issue c.pfaffenbichler you were on the right track, it just wasn't quite implemented right in the loops.

                               

                               

                              dgolberg