I cannot seem to lose the reference to the original array I'm trying to clone. To illustrate my problem concretely, suppose I have the following.
student.scores: Array[3]
0: 12
1: 97
2: 81
My dropLowestScores
method then intends to find the two lowest values in the scores
array, copies them and put them in property lowest
.
student.lowest: Array[2]
0: 12
1: 81
Unfortunately, while I get the correct values in lowest
, rather than copying them from scores
, they are spliced. Not only that, but all values from my original array are depleted.
student.scores: Array[0]
This might make sense, given that I'm calling knockout's splice
method, but I'm calling it on a copy of the scores
array where I first called splice(0)
! I'm not sure if it matters, but the observable array I am splicing consists of observable numbers.
See the script below for details, or the JSBin above for the full thing.
Note that student
is just the model I'm working with.
this.dropLowestScores = function() {
// find lowest scores for each student
ko.utils.arrayForEach(_this.students(), function(student){
//sporting function for observable values in array
var comparator = function(a,b){
if(a()<b()){
return -1;
} else if(a() > b()){
return 1;
} else {
return 0;
}
};
// tmp is a sorted clone of scores
var tmp = student.scores().sort(comparator).splice(0);
// set lowest to last two values in tmp array
student.lowest = tmp.splice((tmp.length-2),tmp.length);
// see what I'm getting
console.log(student.fullName());
console.log('student lowest: ' + student.lowest.length);
console.log('student scores: ' + student.scores().length);
});
};
As edhedges pointed out, slice
is the correct method. The comparator
was also sorting opposite of how I intended.
A further point is that I cannot sort until tmp
is created, else it updates the view, which I do not desire.
The final version should look like the following.
this.dropLowestScores = function() {
ko.utils.arrayForEach(_this.students(), function(student){
var comparator = function(a,b){
if(a()<b()){
return 1;
} else if(a() > b()){
return -1;
} else {
return 0;
}
};
var tmp = student.scores().sort(comparator).slice(0);
student.lowest = tmp.splice((tmp.length-2),tmp.length-1);
});
};
The main issue you are having here is that you called splice
and should have called slice
.
As you can see slice is what you are trying to accomplish, but you used splice with no second argument so your array was getting wiped.
Once this was fixed you still had a problem in your comparator
function. You were returning the two highest not the two lowest.
// updated dropLowestScores
this.dropLowestScores = function() {
ko.utils.arrayForEach(_this.students(), function(student){
var comparator = function(a,b){
if(a()<b()){
return 1;
} else if(a() > b()){
return -1;
} else {
return 0;
}
};
var tmp = student.scores.slice(0).sort(comparator);
student.lowest = tmp.splice((tmp.length-2),tmp.length);
console.log(ko.toJSON(student.lowest));
console.log(ko.toJSON(student.scores));
});
};