Array.sort() compare strangeness function in ExtendScript

I write this in InDesign Scripting forum, because I met the problem while he was working on a script for InDesign CC 2015, but it seems to cover all of ExtendScript.

In my script, I use the method array.sort() with a custom comparison function to sort an array of objects with respect to one of their properties. I will introduce a version widespread in the party so that it is easier to analyze and reproduce.

var myArray = [{
    name: "A",
    size: 20
}, {
    name: "B",
    size: 10
}, {
    name: "C",
    size: 30
}, {
    name: "D",
    size: 30
}];

myArray.sort(
    function(a, b) {
        if (a.size > b.size) {
            return 1;
        }
        if (b.size > a.size) {
            return -1;
        }
        return 0;
    });


var names = [];
for (var i = 0; i <= myArray.length - 1; i++) {
    names.push(myArray[i].name)
};
names;

The expected result is "B, A, C, D. B must go before A, as its size is smaller than A, while C and D should remain unchanged, because their size is equal.

However, the result provided by ExtendScript is "B, A, D, C. For some reason, C and D become reversed.

I believe that the source of this behavior lies with incorrect treatment of ExtendScript part returns 0 .

To confirm that, I replaced the triage function with

myArray.sort(
    function(a, b) {
        return 0;
    });

which, according to my understanding of how the comparison functions are supposed to work, must return the entire unchanged table (regardless of the entry). But in this case ExtendScript treats as "B, C, D, A.

I would be very grateful if someone could confirm if it is indeed a bug (or at least a dull implementation of the ECMAScript standard). Or is everything works as it should and the error on my part?

Advice as workaround for this problem would also be very useful. Thank you!

Thanks for that suggestion!

Your answer made me read on different algorithms sort and their implementation in the different JavaScript engines. Apparently, ExtendScript uses what is called an unstable sorting algorithm, which is precisely the cause of a non desired behavior with values of the sort condition.

To implement a different and stable algorithm (for example, merge sort) in your script is certainly an option, but it seemed overkill for my purposes.

Fortunately, I was able to find another solution.

First, add a property 'position' for each element of the array, based on its current position. For example:

for (i = 0; i < myArray.length; i++) myArray[i].position = i;

Then, simply change the latest state of the sort function so that it compares the position of each element:

myArray.sort(function(a, b) {
    if (a.size > b.size) {
        return 1;
    }
    if (b.size > a.size) {
        return -1;
    }
    if (a.size == b.size) {
        return a.position - b.position;
    }
});

I hope this will be useful to those who might encounter the problem in the future.

Tags: InDesign

Similar Questions

  • Array.sort is unstable?

    Use Array.sort, when the compareFunction always retrun 0, it will change the order of the elements in array. (in javascript, is not)

    is the quick sorting using Array.sort, which is unstable?

    and how to fix it not change the order of the elements.

    Thanks for any help.

    Here's the test code:

    Student.As

    package
    {
              public class Student
              {
                        public function Student(name:String, age:int)
                        {
                                  this.name = name;
                                  this.age = age;
                        }
      
                        public var age:int;
      
                        public var name:String;
      
                        public function toString():String
                        {
                                  return "[name=" + name + " age=" + age + "]";
                        }
              }
    }
    
    

    Applicatoin.MXML

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                                            creationComplete="application1_creationCompleteHandler(event)">
              <mx:Script>
                        <![CDATA[
                                  import mx.events.FlexEvent;
      
                                  private var ac:Array = [
                                            new Student("ST1", 21),
                                            new Student("ST2", 21),
                                            new Student("ST3", 21),
                                            new Student("ST4", 21)
                                  ];
      
                                  protected function application1_creationCompleteHandler(event:FlexEvent):void
                                  {
                                            ac.sort(function(a:Object, b:Object):int
                                            {
                                                      if (a.age > b.age)
                                                                return 1;
                                                      else if (a.age < b.age)
                                                                return -1;
                                                      return 0;
                                            });
                                            trace(ac);
                                  }
      
                        ]]>
              </mx:Script>
      
    </mx:Application>
    
    

    the result is:

    [name=ST3 age=21],[name=ST2 age=21],[name=ST1 age=21],[name=ST4 age=21]
    

    Array.sort has change the order of the elements in array

    See http://stackoverflow.com/questions/3026281/array-sort-sorting-stability-in-different-brows ers

    Array.sort is not necessary to be stable according to ECMA.  Looks like the recent browsers have implemented a stable sort, but Flash does not.

    AS3Commons claims to have a stable sort.  See http://code.google.com/p/as3-commons/source/browse/trunk/as3-commons-collections/src/main/ actionscript/org/as3commons/collections/utils/ArrayUtils.as

  • Built-in sort with Arrays.sort

    I have multidimensional array that contains a number as new arr int [10] [10] and that you want to sort according to the last column. Arrays.sort is a simple way to do it, but what happens if I don't want a real movement elements occur by Arrays.sort (arr [] []). Frankly, I'm interested in winning positions but not to grant the lines. Can I pass it arrange step because not interested in changing the original table? For the moment, I sort the table with Arrays.sort then index of table row and I fixed the position number pair. For example arr [0] has rank 1, arr [1] has the rank of 2 etc. If sorted according to the last column.

    Published by: totalnewby on May 23, 2011 22:51

    totalnewby wrote:
    I just need to know where the items would be positioned if they have been sorted. I made copy of the table at the moment and my program is successful, even if it takes a lot of time and additional memory to perform the copy because this table has billions lines in reality. If you can suggest less time-consuming solution do let me know.

    This is my standard example of how to do this sort of indirect.

     public static void main(String[] args) throws Exception
        {
            final Words words = new Words("/usr/share/dict/words");
            final List data = new ArrayList();
            for (int i = 0; i < 10000; i++)
            {
                String[] row = new String[10];
                for (int j = 0; j < row.length; j++)
                {
                    row[j] = words.getRandomWord();
                }
                data.add(row);
            }
    
            final Integer[] indirectIndex = new Integer[data.size()];
            for (int i = 0; i < indirectIndex.length; i++)
            {
                indirectIndex[i] = i;
            }
    
            final Comparator indexComparator = new Comparator()
            {
                @Override
                public int compare(Integer left, Integer right)
                {
                    int result = 0;
                    for (int i = 0; result == 0 && i < data.get(left).length; i++)
                    {
                        result = data.get(left).compareTo(data.get(right)[i]);}return result;}};
    
    Arrays.sort(indirectIndex, indexComparator);
    
    for (int i = 0; i < 100; i++){System.out.println(indirectIndex[i] + "\t" + Arrays.toString(data.get(indirectIndex[i])));}}
    
    You just need to create a Comparator for sorting the index array that uses the last entry in each row of real data array when comparing a row rather than all the row entries as I have done. 
    
  • Arrays.sort

    Why did the Arrays.sort method defined as

    public static sort (Object [] a) Sub

    Instead of

    public static sorting Sub (comparable [] a)?

    user9987428 wrote:

    jverd wrote:
    In this way we can sort an array whose elements are all mutually comparable, even if the table itself is not declared as being of a Comparable type. I can't think of a specific use case where it would be useful, but that's the only reason why I can think for deliberately to make that decision.

    Dear jverd, I'm not sure that the case you are referring. I tried the following code and it gives a runtime Exception.

    The current implementation does not allow it and even though I was thinking exactly the same thing as jverd suggested, I think it is more likely that it's just an oversight.

  • Unexpected result with Array.sort

    There seems to be a problem with the sort function when sorting the table contains several elements that are equal. I tried to illustrate this in the most simple form below:

    var test1:Array = ['a', 'b', 'this,' would be '];

    var test2:Array = [', 'c', 'b', 'a'];

    var test3:Array = ['a', 'b', 'c', ' a'];

    var test4:Array = ['a', ' a ',' b ', 'a'];

    trace (test1.sort (Array.RETURNINDEXEDARRAY)); Should be 0,1,2,3 (well!)

    trace (test2.sort (Array.RETURNINDEXEDARRAY)); Should be 3,2,1,0 (good!)

    trace (test3.sort (Array.RETURNINDEXEDARRAY)); Must be 0,2,3,1 (evil)

    trace (test4.sort (Array.RETURNINDEXEDARRAY)); Must be 0,1,3,2 (evil)

    / * Output

    0,1,2,3

    3,2,1,0

    3,0,1,2

    3,1,0,2

    */

    Can anyone find a reason of incompatibility, or is this a bug in the sorting method?

    test3: must be 0,3,1,2 or 3,0,1,2.  They are the same.

    test4: 0,1,3,2 is the same as 3,1,0,2 is the same as 1,0,3,2 is the same as 0,3,1,2 etc.  That is to say, as long as the index 2 is the last, they still.

    Oh, I see the problem.  you think flash is assign an index to the elements of the original array.

    It is not the case.  the method released the list of indices in the sort order.  IE, 0,3,1,2 means the original elements of 0th and 3rd tables are first and 2nd and the 1st element is the third and the 2nd element is the last.

    so, if you wanted to list the elements of original paintings using your sort order for test3, for example, you would use:

    test3 [0], test3 [3], test3 [1], test3 [2] and you expect, a, b, c

  • Creating datagrid with sorting options &amp; filter function

    function createDatagrid():

    DataGrid

    var dp:DataProvider = new DataProvider();

    AddIn entries

    for (var i = 0; i < = guestlistArray.length - 1; i ++) {}

    var str_guestlist:String = guestlistArray [i];

    var guestlistColArray:Array = str_guestlist.split(",");

    dp.addItem ({id: guestlistColArray [0], name: guestlistColArray [1] last_name:guestlistColArray [2],})

    designation: guestlistColArray [3], e-mail: guestlistColArray [4], [5], mobile: guestlistColArray

    Office: guestlistColArray [6], company: guestlistColArray [7] barcode:guestlistColArray [8],

    Photo: guestlistColArray [9] table_no:guestlistColArray [10], [11], of participation: guestlistColArray

    arrival_time:guestlistColArray[12]});

    }

    QUESTION: All these needs entrances around some sounds loading, is there any code that I can use to view the progress of the loading, 0% - 100%?

    reset the entry from the table

    guestlistColArray = new Array();


    QUESTION: What is the best way to remove all of the entries in a table?

    //give every col, a name

    myDataGridList.columns = ['id', 'name', 'name', 'description', 'email', 'mobile', 'office',

    'barcode', 'photo', 'table_no', 'presence', 'society', "arrival_time"];

    //set display width of col

    myDataGridList.getColumnAt (0) .width = 40;

    myDataGridList.getColumnAt (7) .width = 180;

    //set display names of col

    myDataGridList.getColumnAt (0) .headerText = "ID";

    .headerText myDataGridList.getColumnAt (7) = "company";

    Set the sorting options

    myDataGridList.getColumnAt (0) .sortOptions = Array.NUMERIC;

    myDataGridList.getColumnAt (7) .sortOptions = Array.CASEINSENSITIVE;

    QUESTION: I need to click on the column first in order to make it work. How can I sort the columns automatically when the datagrid control is created and illustrated?

    myDataGridList.dataProvider = dp;

    creating a filter on top of datagrid bar

    I have a textfield of entry for the user to type something. (txt_filter)

    It filters the data in the datagrid control according to the keywords typed in by the user in the input textfield object.

    Now, the TextField is ready for entry. It should only filter the first_name, last_name.

    QUESTION: How can I make the filter works? How can I open an event listener to detect the pressure inside the txt_filter and filter all the data?

    Hi all

    The above is my doubts to sort a datagrid and a function of filter for datagrid. Hope you could give me some advice on this.

    Thank you

    -Zainuu

    I hope you followed the tutorial image from here, so that you have the same image. He too they have followed the path that have seen us in the tutorial of this law of 16 series.

    http://www.Adobe.com/devnet/flash/QuickStart/datagrid_pt3.html (scroll down and see the image, loading method)

    // Create a new DataGridColumn object, and specify a custom cell renderer.

    var dataCol:DataGridColumn = new DataGridColumn("data");

    dataCol.cellRenderer = LoaderCellRenderer;

    // Create a new DataGridColumn object.

    var titleCol:DataGridColumn = new DataGridColumn("title");

  • An array of strings as function parameter in loop fails

    Hallo,

    I have a weird problem here and I hope someone can help me find the cause.

    I have a function where I said an array of strings (string_list). I pass the array to a function that does modifactions to the table. I am addressing Walker the array of strings to an index of all the values are stored correctly. When I loop through the array by incrementing the index automatically only the last index value are saved in all positions.

    Why is this? Or what I am doing wrong?

    It is the passage to another function, an array of strings
    int calling_function
    {
    char * string_list [MAX_PATHNAME_LEN]; //< store="" strings="" in="">
    function_called (string_list); passing a pointer to an array of string
    return 0;
    }

    This is the function receives a reference to an array of strings to store data
    int function_called (char * output_list [])
    {
    int i = 0; counter variable
    / * This works and good values are stored in output_list * /.
    output_list [0] = '02 ";
    output_list [1] = '12 ';
    output_list [2] = "22";
    output_list [3] = "32";
    output_list [4] = '42 ';
    output_list [5] = "52";
    output_list [6] = '622 ';
    output_list [7] = "72".

    / * This does not work and will store '31' in all places of the matrix * /.
    < 32="">
    {
    < %d »,="" i) ;="" incrémenter="" la="" valeur="">< br=""> output_list [i] = sample; < br=""> i = i ++ ; < br=""> < br="" >="">

    output_list [0] = '02 "; < br=""> output_list [1] = '12 ';< br="" >="">

    Thanks!

    Hi,.

    When you do

    output_list [i] = sample;

    all of the members of the array have the same value: sample-a char pointer. You are modifying the afterwards glad of sample purpose the previous values still point to sample.

    If you assign values to each array member like:

    you assign different values: a pointer to a string containing "02", pointing to a string contaning "12",...

    If you want to assign values in a loop you need to allocate memory for each string (output_list [i]) and copy the content of sample in them.

    Does this make sense to you?

    Constantin

  • How can I index an element of the array as "index Board" function to labview?

    Hello:

    I am looking for a method to search an array with indexes and return the element specified by the given index.

    as the array index of the labview function, but I can't find an exact symbol in teststand-table-operations/functions.

    I am new to teststand and everyone knows how to use labview in teststand.

    anyone can teach me?

    Thanks in advance!

    Thanks anyway, found in the API

  • array sorting

    I have attached a simple VI to power a table the latest values on top.

    Please if someone can suggest a better way.

    Alok.p wrote:

    I have attached a simple VI to power a table the latest values on top.

    Please if someone can suggest a better way.

    I have not uderstand why call you the output terminal iteration "non-random. feed to the range", because it is certainly not a random number as the code ensures that the current number is always greater than any number existing in the table (except in the first iteration where it is equal), the problem, as it is, a meaningless.

    Suppose you have an array of 10 elements (you can also resize the table index to actually show all 10 items, currenty we see only 9) and you want to add the new value to the 0 position (independently!), change of all the other upward with each addition.

    In this case, the following would be a solution that keeps track of the statically allocated table. The elements will always be sorted in historical sort order, newest on top, and the size of the array is fixed to 10 elements, retaining the 10 most recent additions.

    The label of the button is also misleading, because this is a lock, that one element will be added with each press. It should be called "Add item" instead.

    (To run the event structure would be better for the current code (not shown)).

  • Poor supported for string functions in ExtendScript Javascript?

    Differences between JS and JSX is really annoying during the development of the panels, as some things work for one language and not the other.
    I just noticed that the endsWith () - string function does not work in JSX. I'm just checking if a layer name ends with a special character, like this:

    alert("lolk_".endsWith("_"));
    

    This will stop executing the script. Come on! Do I really need to use a regular expression for this kind of things super simple? This is ridiculus!

    [PS script] ExtendScript supported ECMAScript 6th version | Community customer Photoshop family

  • Adobe Acrobat 9 'Compare' missing function.

    I can't find the selection of 'Compare' referring to so many explanations online.  Is it possible that there are 'variants' of Adobe Acrobat 9 Standard which do not have the function 'compare two files?

    Please skip this question.  After some research it turns only 'Standard' has no function to compare two files (although there were contradictory statements on the presence or absence of this command).

  • Input array allocated by the function even if it is not

    I set it up to call the foalT table 4 times to combine with different results.  foalT is a multidimensional array with each element of the element 4 long.   It works perfectly the first time that the function is called foalTotal is correct.  Other times foalT is empty.  It seems that the problem happens when I use original.shift () and then call them recursively function but I have no idea why original happens in the foalT table.  Any help would be appreciated.

    var foalTotal:Array = handset (foalWA, foalT);

    var foalTSC:Array = Combine(foalWASC,foalT);

    var foalTDC:Array = Combine(foalWADC,foalT);

    var foalTBC:Array = Combine(foalWABC,foalT);

    Function Combine(cross:Array,original:Array):Array {}

    var k: uint = 0;

    total var: Array = new Array;

    trace ("foalT length:" + original.length);

    If {(original.length!==0)}

    for (var i: uint = 0; i < cross.length; i ++) {}

    for (var j: uint = 0; j < = 3; j ++) {}

    total [k] = cross [i] .slice ();

    total [k].push(original[0][j]);

                        k++;

    } //end for

    } //end external to

    original.shift ();

    (Combined (total, original)); return

    } //end if

         else

    return (cross);

    { } / / end fuction

    Flex has some degree of use of the references who know you in this case.

    As noted in the previous poster, you must clone the object in this case.

  • Problem strange function

    I have two swf files that I use for this. Loader.swf load loaded.swf in there. Loader.swf tries to call a function that is created in loaded.swf but I can't understand the path to the function. I've linked to two very small files fla for reference.

    Loader.fla
    Loaded.fla

    Thank you!
    -Aaron

    you have the correct path.function name. you wait until the loading is complete before attempting to use the service.

  • Need to sort out my paragraphStyleGroup

    Hi all

    See my script which does not sort below paragraph style. But I need to sort my paragraph styles as well as my group of paragraph style styles.

    Here's the code to sort the paragraph styles:

    myParStyles_Sort (app.activeDocument);
    function myParStyles_Sort (doc)
    {
    var string_array = sort_par_names (doc);
    for (var i = 0; i < string_array.length; i ++)
    () doc.paragraphStyles.item ([i] string_array) .move
    LocationOptions.after, doc.paragraphStyles [i + 2])
    }

    function sort_par_names (doc)
    {
    var table = doc.paragraphStyles.everyItem () .name;
    Array.Shift (); Array.Shift ();
    array.sort return (myCaseInsensitive);
    }
    function myCaseInsensitive (a, b)
    {
    return a.toLowerCase () > b.toLowerCase)
    }

    Some current examples of style sheets

    Picture 13.png

    Need to change this format as indesign made with sort by name option.

    Picture 14.png

    Thanks in advance for your time and support.

    Chang

    You can use a recursion, like this:

    myParStyles_Sort (app.activeDocument);
    function myParStyles_Sort (doc){
        var myItem;
        var myLastItem;
        var string_array = sort_par_names (doc);
        for (var i = 0; i < string_array.length; i++){
            myItem = doc.paragraphStyles.item (string_array[i]);
            if (myItem.hasOwnProperty("paragraphStyles")){
                myParStyles_Sort(myItem);
            }
            if (i == 0){
                myItem.move (LocationOptions.AT_BEGINNING);
            } else {
                myItem.move (LocationOptions.AFTER, myLastItem);
            }
            myLastItem = myItem;
        }
    }
    
    function sort_par_names (doc){
        var firstIndex = doc instanceof Document? 2: 0;
        var myArray = doc.paragraphStyles.everyItem().name.slice(firstIndex);
        myArray = myArray.concat(doc.paragraphStyleGroups.everyItem().name);
        return myArray.sort ();
    }
    
  • ExtendScript quirks with incrementing a value in array

    Just for my curiosity (I'm a very absolute beginner with ExtendScript), but also to better understand Extendscript. I have:

    so that {(myTextFrame.overflows)

    var f = myTextFrame.geometricBounds;

    ++ GB [2];

    myTextFrame.geometricBounds = GB;

    }

    Why can't do, instead

    in (myTextFrame.overflows) ++ myTextFrame.geometricBounds [2];   ?

    It produces an infinite loop...

    Thank you

    Roberto

    When you ask the geometricBounds InDesign calculates values, filled them in an array object and which yields to ExtendScript. Subsequently, it's just a picture, without any magic glue to the native InDesign object. You can modify, add, or remove values, and no one cares.

    Only by assigning the table (or any other table 4 value) return to the geometricBounds of any element on the page, you spend all values back to InDesign.

    Dirk

Maybe you are looking for

  • Can not copy and paste, do not click on "Help" Menu

    Firefox has just updated to 37.0.2, however, this problem existed before the update. When I try to "copy / paste" one Web page to another, I can right-click and 'copy' but when I try to "stick" to another page, I get a menu that says "Save Page As,"

  • Need win 7 drivers for Qosmio X 300

    Hello I had to format my laptop and I need some drivers for Windows7.Is someone can give me those? Can't find them on the Pages of pilot. Drivers for:/ Manager of controllers with remote-Touch Pad Driver Can someone help me with this?

  • Costs through GSP - SK1

    Hello I tried to load my Tablet via case GSP - SK1 and do not work. The keyboard works fine with the Tablet, this isn't a problem. I use diet tablet to connect a cable deal (as in the instructions). With the normal cable, Tablet disconnect of the cas

  • create table 1 d of ellements

    At a point in my program, I want to make a table 1 d of arrayelements selected from a 2d array of entry. When I run my program now you get just a really in my flag, but I need to get all the items stored in a table, so I can work on Pentecost this ta

  • VBAI problem with the calculator tool

    Concern / tested with: VBAI2010 (build 1014091017 2010)