0

Using Python Django I have a view that returns JSON to a template that initializes a global JavaScript variable as such:

<script type="text/javascript">
    coordinates = {{ coordinates | safe}}
</script>

These coordinates have a field called country.

I sort these objects using:

coordinates.sort(sortByCountry); 

My sortByCountry function:

function sortByCountry(x, y) {
   return ((x.fields.country == y.fields.country) ?
            0 : ((x.fields.country > y.fields.country) ? 1 : -1 ));
}

So when I run

coordinates.sort(sortByCountry); 

it returns the correct order of objects.

But if I loop through coordinates it loops through as if it has not been sorted. Here for each country i correct a new array and push them in so all coordinates that belong to the same country are in the same array. All these arrays are nested in another array called countries.

        var countries = [];
        var counter = 0; // number of countries
        function sortByCountry(x, y){
                return ((x.fields.country == y.fields.country) ? 0 : ((x.fields.country > y.fields.country) ? 1 : -1 ));
        }
        function country_assignment(){
                coordinates.sort(sortByCountry); // ****This works returns a sorted coordinates list, can even do window.coordinates and get the sorted list
                countries.push(new Array());
                countries[counter].push(coordinates.pop());
                length = coordinates.length
                for( var l = 0;  l < length; l++){

                      //this loops through coordinates as if it was not sorted
                        if((countries[counter][0].fields.country == coordinates[0].fields.country)){


                                countries[counter].push(coordinates.pop());

                        } else {

                                countries.push(new Array());
                                counter = counter + 1;
                                countries[counter].push(coordinates.pop());

I've tried

coordinates = coordinates.sort(sortByCountry); 

But this does not work as well.

Example of JSON objects:

<script type="text/javascript">
        coordinates = [{"fields": {"latitude": 38.5512238, "country": "USA", "location": "802 D St, Davis, CA 95616, USA", "longitude": -121.7441921, "visited": true}, "model": "mapper.destination", "pk": 1}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 2}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 3}, {"fields": {"latitude": 13.7524008, "country": "Thailand", "location": "Na Phra Lan Rd, Khwaeng Phra Borom Maha Ratchawang, Khet Phra Nakhon, Krung Thep Maha Nakhon 10200, Thailand", "longitude": 100.490729, "visited": true}, "model": "mapper.destination", "pk": 4}, {"fields": {"latitude": 51.5073509, "country": "Britian", "location": "London, UK", "longitude": -0.1277583, "visited": true}, "model": "mapper.destination", "pk": 5}, {"fields": {"latitude": 51.1802192, "country": "Britian", "location": "Salisbury, Wiltshire SP4 7DE, UK", "longitude": -1.8270873, "visited": true}, "model": "mapper.destination", "pk": 6}, {"fields": {"latitude": 7.9519331, "country": "Thailand", "location": "Phuket, Thailand", "longitude": 98.33808839999999, "visited": true}, "model": "mapper.destination", "pk": 7}, {"fields": {"latitude": 25.7616798, "country": "USA", "location": "Miami, FL, USA", "longitude": -80.1917902, "visited": true}, "model": "mapper.destination", "pk": 8}]
        </script>
Kyle Calica-St
  • 2,629
  • 4
  • 26
  • 56
  • 1
    Please edit your question to include all of the relevant code. – Jordan Running Dec 04 '15 at 21:20
  • Do you want the for loop as well? Its just a simple for loop ill add it right now. – Kyle Calica-St Dec 04 '15 at 21:22
  • Could you add a sample of a few coordinates? Something kike, `coordinates = [ {fields:{country:??}}, {fields:{country:??}} ]`? – Kenney Dec 04 '15 at 21:22
  • It sounds like it might be an error somewhere else in your code. As Jordan has said, please include ALL relevant code. – Adam P Dec 04 '15 at 21:23
  • Array.prototype.sort() returns a sorted array and does not mutate the arrays it's called on. – louisbros Dec 04 '15 at 21:24
  • i can add the print example, sorry working on one computer and posting the other on this one. – Kyle Calica-St Dec 04 '15 at 21:26
  • @louisbros You are mistaken. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort – Jordan Running Dec 04 '15 at 21:27
  • @louisbros thats what i thought as well but i then saw the MSDN article – Kyle Calica-St Dec 04 '15 at 21:29
  • Sorry my bad. That seems strange. – louisbros Dec 04 '15 at 21:30
  • See: http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript – Jakub Barczyk Dec 04 '15 at 21:35
  • @JakubBarczyk it does the sort fine. If I go to the console in chrome or firefox and type: window.coordinates it returns the sorted order, but if i use them as the example i am going to post then it loops through it as if was not mutable. In that post i believe that person is just trying to sort something – Kyle Calica-St Dec 04 '15 at 21:40
  • it changes in my else statement, only when a new country is encountered. – Kyle Calica-St Dec 04 '15 at 21:51
  • im popping off coordinates and pushing them into the array nested in countries. It works, at the end i get a bunch of arrays and Britan is all contained in one(only cause they are all together anyway) but my USAs are in separate arrays because its not sorted right. this only works if sorting is correct – Kyle Calica-St Dec 04 '15 at 21:53

1 Answers1

1

You code works fine. The coordinates are split up into separate arrays, still sorted. They are, however, sorted backwards, because you take elements from the end with coordinates.pop().

Here's a working demo:

function sortByCountry(x, y){
    return x.fields.country == y.fields.country ? 0 : ( x.fields.country > y.fields.country ? 1 : -1 );
}

function country_assignment(coordinates) {
  
  dump(coordinates,'unsorted');
  
  coordinates.sort(sortByCountry);  
  
  dump(coordinates,'sorted');
  
  var countries = [];
  var counter = 0; // number of countries

  countries.push(new Array());
  countries[counter].push(coordinates.pop());
   
  while ( coordinates.length )
  {
    var c = coordinates.pop();
    if ( countries[counter][0].fields.country == c.fields.country )
      countries[counter].push(c);
    else {
      countries.push(new Array());
      counter ++;
      countries[counter].push(c);
    }
  }
  
  for ( var c in countries )
    dump(countries[c], c); 
}

function dump(coordinates,label) { 
  document.getElementById('debug').innerHTML += 
    "===DUMP=== " + label + "\n"
    + coordinates.map(function(f,i){return f.pk + ": "+f.fields.country;}).join("\n")
    +"\n\n";
}

country_assignment(
  [{"fields": {"latitude": 38.5512238, "country": "USA", "location": "802 D St, Davis, CA 95616, USA", "longitude": -121.7441921, "visited": true}, "model": "mapper.destination", "pk": 1}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 2}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 3}, {"fields": {"latitude": 13.7524008, "country": "Thailand", "location": "Na Phra Lan Rd, Khwaeng Phra Borom Maha Ratchawang, Khet Phra Nakhon, Krung Thep Maha Nakhon 10200, Thailand", "longitude": 100.490729, "visited": true}, "model": "mapper.destination", "pk": 4}, {"fields": {"latitude": 51.5073509, "country": "Britian", "location": "London, UK", "longitude": -0.1277583, "visited": true}, "model": "mapper.destination", "pk": 5}, {"fields": {"latitude": 51.1802192, "country": "Britian", "location": "Salisbury, Wiltshire SP4 7DE, UK", "longitude": -1.8270873, "visited": true}, "model": "mapper.destination", "pk": 6}, {"fields": {"latitude": 7.9519331, "country": "Thailand", "location": "Phuket, Thailand", "longitude": 98.33808839999999, "visited": true}, "model": "mapper.destination", "pk": 7}, {"fields": {"latitude": 25.7616798, "country": "USA", "location": "Miami, FL, USA", "longitude": -80.1917902, "visited": true}, "model": "mapper.destination", "pk": 8}]
);
<pre id='debug'></pre>

There is a slightly easier way to split up the coordinates, by country, though: using objects.

  countries = {};
  while ( coordinates.length )
  {
    var c = coordinates.shift(), 
        f = c.fields.country;

    (countries[ f ] = countries[ f ] || [] ).push( c );
  }

function sortByCountry(x, y){
    return x.fields.country == y.fields.country ? 0 : ( x.fields.country > y.fields.country ? 1 : -1 );
}

function country_assignment(coordinates) {
  
  dump(coordinates,'unsorted');
  
  coordinates.sort(sortByCountry);  
  
  dump(coordinates,'sorted');
  
  var countries = {};  
  while ( coordinates.length )
  {
    var c = coordinates.shift(), 
        f = c.fields.country;
       
    (countries[ f ] = countries[ f ] || [] ).push( c );
  }
  
  for ( var c in countries )
    dump(countries[c], c); 
}

function dump(coordinates,label) { 
  document.getElementById('debug').innerHTML += 
    "===DUMP=== " + label + "\n"
    + coordinates.map(function(f,i){return f.pk + ": "+f.fields.country;}).join("\n")
    +"\n\n";
}

country_assignment(
  [{"fields": {"latitude": 38.5512238, "country": "USA", "location": "802 D St, Davis, CA 95616, USA", "longitude": -121.7441921, "visited": true}, "model": "mapper.destination", "pk": 1}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 2}, {"fields": {"latitude": 51.501009, "country": "Britian", "location": "London SW1A 1AA, UK", "longitude": -0.1415876, "visited": true}, "model": "mapper.destination", "pk": 3}, {"fields": {"latitude": 13.7524008, "country": "Thailand", "location": "Na Phra Lan Rd, Khwaeng Phra Borom Maha Ratchawang, Khet Phra Nakhon, Krung Thep Maha Nakhon 10200, Thailand", "longitude": 100.490729, "visited": true}, "model": "mapper.destination", "pk": 4}, {"fields": {"latitude": 51.5073509, "country": "Britian", "location": "London, UK", "longitude": -0.1277583, "visited": true}, "model": "mapper.destination", "pk": 5}, {"fields": {"latitude": 51.1802192, "country": "Britian", "location": "Salisbury, Wiltshire SP4 7DE, UK", "longitude": -1.8270873, "visited": true}, "model": "mapper.destination", "pk": 6}, {"fields": {"latitude": 7.9519331, "country": "Thailand", "location": "Phuket, Thailand", "longitude": 98.33808839999999, "visited": true}, "model": "mapper.destination", "pk": 7}, {"fields": {"latitude": 25.7616798, "country": "USA", "location": "Miami, FL, USA", "longitude": -80.1917902, "visited": true}, "model": "mapper.destination", "pk": 8}]
);
<pre id='debug'></pre>
Kenney
  • 9,003
  • 15
  • 21
  • Wow okay I'll try this. So wait is JavaScript arrays pop() don't pop from the front. I thought they work like as if on a stack? – Kyle Calica-St Dec 05 '15 at 08:39
  • They do work as a stack, and yes, `pop()` removes from the end, just like `push()` appends to the end. To manipulate the front, you `unshift()` to prepend, and `shift()` to remove. Think of a stack as an array, where the first element is the first one pushed, the last element the last one pushed. It's a [LIFO queue](https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29). – Kenney Dec 05 '15 at 14:10
  • Oh yeah I just realized I was thinking of it backwards. Haha oh man I'll never forget this one now haha thanks! – Kyle Calica-St Dec 05 '15 at 17:04
  • could you explain this line: (countries[ f ] = countries[ f ] || [] ).push( c ); I've never seen a boolean operator be used like that I think it's stating if countries[f] = countries[f] exists then just push in countries[f] else just make a new array in as countries[f] and then push. Can you verify if that is correct? – Kyle Calica-St Dec 06 '15 at 00:21