SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Sort Associative Array - Prototype Issue

    Hello everyone,

    I am building a customised javascript prototype to sort an associative array on the array key (in ascending order).

    Basically, I am separating the array keys into a separate array and then using .sort() to sort the keys and then reassembling the original associative array elements according to the sorted keys array.

    The sorting works ok except that when I run the test code below, the outputed sorted associative array has an extra element at the end of the array whose key is the name of the prototype function and the value for that element is the function code itself.

    Obviously I am misunderstanding something about associative arrays or how javascript prototypes work.

    Any help or solution on how to output a sorted associative array without the extra element will be much appreciated.


    Code:
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <script type="text/javascript">
     
    /**********************************************
    Prototype to sort an associative array
    ***********************************************/
     
    Array.prototype.sortAssoc = function() {
     
    //separate the keys into an array
    var keys = new Array();
    for(var i in this) {
           keys.push(i);
    }
     
    //now sort the keys
    keys.sort();
     
    //build the sorted array
    var sortedArray = new Array();
    for(var i=0; i < keys.length-1; i++) {
              sortedArray[keys[i]] = this[keys[i]];
    }
     
    return sortedArray;
     
    }
     
    //***** testing code **************
    var myArray = [];
    myArray['bbb'] = 'b_red';
    myArray['aaa'] = 'a_green';
    myArray['ccc'] = 'c_blue';
     
    //sort the above array
    var arraySorted = [];
    arraySorted = myArray.sortAssoc();
     
    //display the results
    for(var i in arraySorted) {
             document.write(i+" = "+arraySorted[i]+'<br /><br />');
    }
     
    </script>
    </head>
    <body>
    </body>
    </html>

  2. #2
    SitePoint Guru
    Join Date
    Sep 2006
    Posts
    731
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's happening here:
    Quote Originally Posted by Kalon View Post
    Code:
    //separate the keys into an array
    var keys = new Array();
    for(var i in this) {
           keys.push(i);
    }
    for-in can pick-up other properties and while there may be some esoteric way to distinguish them, you could just use a stand alone function to avoid the problem.
    Code:
    function sortAssoc( arr ) 
    {
     var keys = new Array();
     
     for( var i in arr ) 
      keys.push(i); 
    
     keys.sort();
     
     var sortedArray = new Array();
     
     for( var i = 0; i < keys.length; i++ )  
       sortedArray[keys[i]] = arr[keys[i]];
     
     return sortedArray;
    }
    I'm not sure what the point of this is.
    Tab-indentation is a crime against humanity.

  3. #3
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Logic Ali,

    Thank you for your reply.

    Yes I thought it was happening where you said hence why I have a -1 further down in my code

    Code:
     
    for(var i=0; i < keys.length-1; i++) {
    which made no difference to the output. That really through me into a spin

    After my initial post I too put the code in a function instead similar to yours and it works fine but I was hoping to add the prototype to my prototype.js library

    What I am doing here is I have a client web page with a long list of subheadings, wrapped in <a> tags with content for each subheading. The subheadings are in the client's requested order (not alphabetical) but the inline links at the top of the page to each subheading are in alphabetical order.

    I am building an associative array (using javascript DOM methods) containing the subheading title (as key) and the href of each subheading's <a> as the value. I will now use this associative array to dynamically generate the links at the top of the page to each subheading.

    This way, when subheadings and their content are added or removed the links at the top will be automatically updated and kept in alphabetical order regardless of the order of the subheadings on the actual page.

  4. #4
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,608
    Mentioned
    24 Post(s)
    Tagged
    1 Thread(s)
    JavaScript associative arrays are basically just a different notation for accessing objects and when you access an object using for-in ALL of its properties and methods (apart from the not enumerable ones) are processed. If you just want to process the properties then you need to use the length to control the loop iterations instead of a for-in since a for-in will copy the length as well as the other values that you want.

    Instead of

    Code:
    for( var i in arr ) 
      keys.push(i);
    use

    Code:
    for( var i = arr.length-1; i >= 0; i--) 
      keys.push(arr[i]);
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  5. #5
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi felgall.

    Thank you for your help.

    I have made the change you suggested but unfortunately the ouput from the prototype function uis still not correct.

    For debugging purposes I put an alert(this.length) at the top of the function and it pops up a value of 0 which explains why the document.write() at the end of the function now only outputs a single element in the sorted array - the key = the function name and the value is the function code itself.

    Below is the test code as it stands at the moment.

    What am I still misunderstnding?

    btw - putting the prototype function code in a separate function results in the ouput of a correctly sorted array and so that is my plan B but I would prefer to have the sorting function as a prototype and so I am perservering with this.

    Code:
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <script type="text/javascript">
     
    /**********************************************
    Prototype to sort an associative array
    ***********************************************/
     
    Array.prototype.sortAssoc = function() {
     
    //alert(this.length);
     
    //separate the keys into an array
    var keys = new Array();
    
    for( var i = this.length-1; i >= 0; i--) {
      keys.push(this[i]);
    }
     
    //now sort the keys
    keys.sort();
     
    //build the sorted array
    var sortedArray = new Array();
    for(var i=0; i < keys.length; i++) {
              sortedArray[keys[i]] = this[keys[i]];
    }
     
    return sortedArray;
     
    }
     
    //***** testing code **************
    var myArray = [];
    myArray['bbb'] = 'b_red';
    myArray['aaa'] = 'a_green';
    myArray['ccc'] = 'c_blue';
     
    //sort the above array
    var arraySorted = [];
    arraySorted = myArray.sortAssoc();
     
    //display the results
    for(var i in arraySorted) {
             document.write(i+" = "+arraySorted[i]+'<br /><br />');
    }
     
    </script>
    </head>
    <body>
    </body>
    </html>

  6. #6
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,608
    Mentioned
    24 Post(s)
    Tagged
    1 Thread(s)
    What about an if statement inside the first for-in then to skip the push() for those properties/methods you don't want included.
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  7. #7
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ok, I've added an IF to filter out the properties I don't want and added some more alerts() to see what is going on at each stage.

    There is something strange going on here and I am starting to think this has something to do with the way prototype objects/functions work which I don't understand yet.

    What is really strange to me is that in this snippet

    Code:
    //build the sorted array
    var sortedArray = new Array();
    for(var i=0; i < keys.length; i++) {
              //alert(keys[i]); //this alert outputs values - aaa, bbb, ccc
              sortedArray[keys[i]] = this[keys[i]];
    }
    the alert() outputs the expected c orrect values

    but immediately below this loop this debugging snippet

    Code:
    //this for loop is for debugging only
    for(var i in sortedArray) {
     alert(i);  ////this alert outputs values - aaa, bbb, ccc, sortAssoc
    }
    outputs as above but with the additional element with key = 'sortAsscoc'.

    It appears to me that no matter what code logic I use, something in javascript is appending prototype name and code to my array.

    If you have a few minutes, I would appreciate it if you could have a look at the latest full test code below with the alerts() and their ouputs in comments next to them and see if you can makes sense of what is happening here.

    Thank you again for your help.

    Code:
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <script type="text/javascript">
     
    /**********************************************
    Prototype to sort an associative array
    ***********************************************/
     
    Array.prototype.sortAssoc = function() {
     
    //separate the keys into an array
    var keys = new Array();
    for(var i in this) {
    
     //alert(i); //this alert outputs values - bbb, aaa, ccc, sortAssoc
       
    if(i != 'sortAssoc') {
    
         //alert(i);  //this alert outputs values - bbb, aaa, ccc
        
     keys.push(i);
       }
    }
     
    //now sort the keys
    keys.sort();
     
    //build the sorted array
    var sortedArray = new Array();
    for(var i=0; i < keys.length; i++) {
    
              //alert(keys[i]); //this alert outputs values - aaa, bbb, ccc
              
    sortedArray[keys[i]] = this[keys[i]];
    }
     
    //this for loop is for debugging only
    for(var i in sortedArray) {
    
     alert(i);  ////this alert outputs values - aaa, bbb, ccc, sortAssoc
    
    }
     
    return sortedArray;
     
    }
     
    //***** testing code **************
    var myArray = [];
    myArray['bbb'] = 'b_red';
    myArray['aaa'] = 'a_green';
    myArray['ccc'] = 'c_blue';
     
    //sort the above array
    var arraySorted = [];
    arraySorted = myArray.sortAssoc();
     
    //display the results
    for(var i in arraySorted) {
             document.write(i+" = "+arraySorted[i]+'<br /><br />');
    }
     
    </script>
    </head>
    <body>
    </body>
    </html>

  8. #8
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ahhh, the penny has finally dropped

    As they say - if it looks like a duck and it quacks like a duck then it probably is a duck.

    But unfortunately the same can't be said in javascript

    If it looks like an associative array and it feels like an associative doesn't mean it is an associative array

    After a bit of googling I see that javascript doesn't have associative arrays but they are instead simply objects with properties as you all alluded to earlier.

    Spmeone posted elsewhere that myArray['name'] = 'fred' is essentially the same as myArray.name = 'fred' and that explains why the prototype function is included in my "associative array" - because it is a property of the array I am trying to sort.

    Anyway, my plan B (as was also suggested by Logic Ali) is now my plan A - put the prototype code in a separate function and everything works 100&#37; without any problems.

    Thank you to those that helped - it's much appreciated as I learnt something new today

  9. #9
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,608
    Mentioned
    24 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Kalon View Post
    Thank you to those that helped - it's much appreciated as I learnt something new today
    Any day when you learn something is a good day.

    Rereading my original post which I wrote early this morning I can see that I didn't make it as clear as I should have that JavaScript doesn't have associative arrays.
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •