Pregunta

Background

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.

JSBin: http://jsbin.com/fehoq/168/edit

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.

JS

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);
    });
};

Update

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);
    });
};
¿Fue útil?

Solución

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));
    });
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top