Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sorting arrays not working as expected

<<if $ArraySort == "Name A-Z">>
<<set $Array to $Array.sort(function(a, b){if(a.Name < b.Name) return -1; if(a.Name > b.Name) return 1; return 0;})>>
<<elseif $ArraySort == "Name Z-A">>
<<set $Array to $Array.sort(function(a, b){if(a.Name > b.Name) return -1; if(a.Name < b.Name) return 1; return 0;})>>
<<elseif $ArraySort == "Age 1-2">>
<<set $Array to $Array.sort(function(a, b){return a.Age-b.Age})>>
<<elseif $ArraySort == "Age 2-1">>
<<set $Array to $Array.sort(function(a, b){return b.Age-a.Age})>>
<</if>>

This is an older project that wasn't fully tested before I mothballed it, that I am now trying to get up and running again.

This is an attempt to sort the objects inside the array, using a method I believe I lifted from another game. All four values for $ArraySort (and thus all four methods of sorting the array) produce the same error message; "Error: <<set>>: bad evaluation: undefined is not a function".

About three lines below that error message is evidence that the array in question does indeed contain objects that have a .Name and a .Age property.

The passage comments contain an alternative method:
<<if $ArraySort == "Name A-Z">>
<<script>>
$Array.sort(function (a, b) {
var
NameA = a.Name.toUpperCase(),
NameB = b.Name.toUpperCase();
if (NameA < NameB) {
return -1;
}
else if (NameA > NameB) {
return 1;
}
return 0;
});
<</script>>
<<elseif $ArraySort == "Name Z-A">>
<<script>>
$Array.sort(function (a, b) {
var
NameA = a.Name.toUpperCase(),
NameB = b.Name.toUpperCase();
if (NameA > NameB) {
return -1;
}
else if (NameA < NameB) {
return 1;
}
return 0;
});
<</script>>
<<elseif $ArraySort == "Age 1-2">>
<<script>>
$Array.sort(function (a, b) {
return a.Age - b.Age;
});
<</script>>
<<elseif $ArraySort == "Age 2-1">>
<<script>>
$Array.sort(function (a, b) {
return b.Age - a.Age;
});
<</script>>
<</if>>

This produces a different error; "<<script>>: bad evaluation: $Array is not defined".

Any idea how to take one or both of these early drafts and turn it into something that works?

In case it isn't obvious, the four 'sorting options' I'm using are alphabetically ascending/descending by the 'Name' property, and numerically ascending/descending by the 'Age' property.

I am using SugarCube 2.7.2 on Twine 2.0.11

Comments

  • edited November 2016
    I'm not sure about the other sort methods, but if you want to sort everything from A-Z, all you need is

    <<print $Array.sort()>>
    


    My mistake! I forgot you were sorting objects, not just array variables.

    JavaScript inside the <<script>> tags will not pull variables from outside the <<script>> tags. Your solution needs to either happen entirely inside of JavaScript (using functions to pull info from the HTML in order to determine the sorting method and to grab the array), or it needs to be done using just Twine and SugarCube.

    It might help if you post the rest of the relevant code so we can see how you're defining everything and filling up the array.

    I was not able to figure out sorting by name, but I did get it for the age sorting.

    Note: When you use the .sort() method, it automatically assigns the new array. You only need <<set $array.sort()>> to get the new array, rather than <<set $array to $array.sort()>>.

    Here's what I have:
    <<set $arraySort to "Name A-Z">>
    <<set $array to ["Josh", "Steven", "Rob", "Jeff", "Edgar", "Alex"]>>
    <<set $arrayNum to [0, 8, 9, 33, 4, 1, 88]>>
    <<set $arrayObj to [{name: "Josh", age: 33},{name: "Alex", age: 78},{name: "Zack", age: 4}]>>
    <<if $arraySort is "Name A-Z">>
    <<set $arrayObj.sort(function(a,b){return a.name - b.name;})>>
    <<elseif $arraySort is "Name Z-A">>
    <<set $arrayObj.sort(function(a,b){return b.name - a.name;})>>
    <<elseif $arraySort is "Age 1-2">>
    <<set $arrayObj.sort(function(a,b){return a.age - b.age;})>>
    <<elseif $arraySort is "Age 2-1">>
    <<set $arrayObj.sort(function(a,b){return b.age - a.age;})>>
    <<else>>
    <<print "Invalid sorting method">>
    <</if>>
    <<for _i = 0; _i < $arrayObj.length; _i++>>
    <<print "Name: " + $arrayObj[_i].name + ", Age: " + $arrayObj[_i].age>>
    <</for>>
    

    That works for both age sorting, but not for names. I'm not sure how to get the name sorting working.
  • Please use the code tag when posting code—it's C on the editor bar.
    PostingAlt wrote: »
    This is an attempt to sort the objects inside the array, using a method I believe I lifted from another game. All four values for $ArraySort (and thus all four methods of sorting the array) produce the same error message; "Error: <<set>>: bad evaluation: undefined is not a function".
    You didn't show all of the code involved, so it's difficult to say what is wrong.

    PostingAlt wrote: »
    The passage comments contain an alternative method: […]

    This produces a different error; "<<script>>: bad evaluation: $Array is not defined".
    As noted in the <<script>> macro's documentation, it evaluates pure JavaScript code, not TwineScript. To access story variables within a <<script>> invocation, you'd need to use the State.variables property or the variables() function. For example:
    → Via State.variables
    State.variables.Array
    
    → Via variables()
    variables().Array
    


    PostingAlt wrote: »
    I am using SugarCube 2.7.2 on Twine 2.0.11
    You're four releases behind—SugarCube v2.11.0 is the current release.

    Naweth wrote: »
    Note: When you use the .sort() method, it automatically assigns the new array. You only need <<set $array.sort()>> to get the new array, rather than <<set $array to $array.sort()>>.
    That's not quite correct—so, no and yes. No—the <Array>.sort() method sorts the existing/original array in-place and returns a reference to it, it does not generate a new array. Yes—since it sorts in-place, there's no need for an assignment, though there's no harm in doing so.


    Anyway. The following works for me:
    <<silently>>
    	<<set $Array to [
    		{ Name : "Josh", Age : 33 },
    		{ Name : "Alex", Age : 78 },
    		{ Name : "Zack", Age : 4  }
    	]>>
    	<<set $ArraySort to "Name A-Z">>
    	<<switch $ArraySort>>
    	<<case "Name A-Z">>
    		<<set _sortFn to function (a, b) {
    			if (a.Name < b.Name) return -1;
    			if (a.Name > b.Name) return 1;
    			return 0;
    		}>>
    	<<case "Name Z-A">>
    		<<set _sortFn to function (a, b) {
    			if (a.Name > b.Name) return -1;
    			if (a.Name < b.Name) return 1;
    			return 0;
    		}>>
    	<<case "Age 1-2">>
    		<<set _sortFn to function (a, b) {
    			return a.Age - b.Age;
    		}>>
    	<<case "Age 2-1">>
    		<<set _sortFn to function (a, b) {
    			return b.Age - a.Age;
    		}>>
    	<</switch>>
    <</silently>>\
    BEFORE:
    \ <<= $Array.map(function (o) { return o.Name + '/' + o.Age; })>>
    
    <<run $Array.sort(_sortFn)>>\
    AFTER:
    \ <<= $Array.map(function (o) { return o.Name + '/' + o.Age; })>>
    
    All sorts were tested and verified as working. I used a temporary variable to hold the selected sorting function, rather than repeating the call to <Array>.sort() multiple times, but that doesn't change how anything works.

    That's not fundamentally different from your original example, so for now I'm going to assume that your issue lies within the structure of $Array itself.
Sign In or Register to comment.