Knockout: больше путаницы с возвращением indexOf -1

Задний план

Я пытаюсь проверить наличие значения в массиве A во втором массиве B. Каждое значение является наблюдаемым числом. Каждое наблюдаемое число содержится в наблюдаемом массиве. Сравнение всегда возвращает -1, что, как известно, неверно (поскольку значения в A и B перекрываются). Следовательно, у меня что-то не так с логикой или синтаксисом, но я не смог понять, где.

JSBin (полный проект): http://jsbin.com/fehoq/182/edit

JS

//set up my two arrays that will be compared
this.scores = ko.observableArray();

//lowest is given values from another method that splices from scores
this.lowest = ko.observableArray();

//computes and returns mean of array less values in lowest
this.mean = (function(scores,i) {
    var m = 0;
    var count = 0;

    ko.utils.arrayForEach(_this.scores(), function(score) {

        if (!isNaN(parseFloat(score()))) {

            //check values
            console.log(score());

            // always returns -1
            console.log(_this.lowest.indexOf(score()));

            //this returns an error, 'not a function'
            console.log(_this.lowest()[i]());

            //this returns undefined
            console.log(_this.lowest()[i]);

            //only do math if score() isn't in lowest
            // again, always returns -1, so not a good check
            if (_this.lowest.indexOf(score())<0) {
                m += parseFloat(score());
                count += 1;
            }
        }

    });

    // rest of the math
    if (count) {
        m = m / count;
        return m.toFixed(2);
    } else {
        return 'N/A';
    }
});

Обновлять

@Major Byte отметил, что mean() вычисляется до того, как что-либо будет перемещено в lowest, поэтому я получаю undefined. Если это так, то как лучше всего обеспечить, чтобы метод mean() обновлялся в зависимости от изменений в lowest?


person Jefftopia    schedule 09.05.2014    source источник
comment
насколько я могу судить, использование переменной i всегда будет терпеть неудачу, если вы не дадите ей значение...   -  person PW Kad    schedule 09.05.2014
comment
i передается ему из привязки данных. Это $index() в foreach.   -  person Jefftopia    schedule 09.05.2014
comment
Из того, что я могу сказать, student.mean выполняется до того, как student.lowest() заполняется/инициализируется, который (student.lowest()), в свою очередь, кажется установленным/заполненным только тогда, когда вы нажимаете кнопку Drop Lowest Score. Или я тут плохо смотрю?   -  person Major Byte    schedule 09.05.2014
comment
Вы знаете, в чем ошибка, по крайней мере, в этот момент?   -  person PW Kad    schedule 10.05.2014
comment
@PWKad, если этот вопрос был адресован мне, то нет, потому что ошибки нет. Но то, что Джеффтопия написал в этом вопросе, это, например, // always returns -1 console.log(_this.lowest.indexOf(score()));, что верно, потому что в этот момент наблюдаемый массив _this.lowest пуст, потому что он устанавливается/заполняется только при нажатии кнопки Drop Lowest Score   -  person Major Byte    schedule 10.05.2014
comment
Хорошая точка зрения. Самый низкий заполняется только тогда, когда я нажимаю кнопку, что интуитивно желательно, учитывая контекст, а именно, что это для журнала оценок. Итак, я понимаю, что по умолчанию любая функция, которая полагается на наблюдаемые, ведет себя как вычисляемая... так что в этом случае, почему не означает обновление? Я явно что-то упускаю.   -  person Jefftopia    schedule 10.05.2014
comment
Думаю, ты прав, @MajorByte; журнал консоли, который я прокомментировал, печатает неопределенное значение, если он записан как console.log(_this.lowest()[i]);. Может быть, он не определен, потому что не имеет значений?   -  person Jefftopia    schedule 10.05.2014
comment
@Jefftopia Этот вопрос был адресован вам, но если он не определен, это не означает, что это ошибка, а только то, что по этому индексу в массиве не существует значения.   -  person PW Kad    schedule 10.05.2014
comment
Верно, но, как я уже упоминал в своем посте, я уже знаю, что есть перекрывающиеся значения. Я использовал плагин отладчика Chrome Knockout и просмотрел содержимое каждого массива... поэтому я не могу сказать, почему проверка не удалась.   -  person Jefftopia    schedule 10.05.2014
comment
@PWKad, ошибка в моем исходном заявлении console.log(_this.lowest()[i]()); была not a function. Обновление исходного сообщения, чтобы прояснить два похожих, но разных оператора журнала и то, что они возвращают.   -  person Jefftopia    schedule 10.05.2014
comment
Что касается вашего добавленного вопроса из последнего редактирования, что может быть лучшим способом гарантировать, что mean() будет обновляться на основе изменений до самого низкого уровня, который вы, вероятно, должны сделать mean a ko.computed. Поскольку оценка вычисляемого mean будет считываться как из наблюдаемых scores, так и из наблюдаемых lowest, вычисляемое mean будет переоцениваться каждый раз при изменении любой из этих наблюдаемых. Я предлагаю вам ознакомиться с документацией по вычисляемым наблюдаемым объектам Knockout.   -  person Robert Westerlund    schedule 10.05.2014
comment
ko.computed не принимает аргументов, поэтому я не думаю, что это сработает. Этот вопрос заставляет меня думать, что обычной функции, которая принимает наблюдаемые в качестве аргументов, должно быть достаточно. stackoverflow.com/questions/23299194/   -  person Jefftopia    schedule 10.05.2014
comment
Почему вы хотите, чтобы аргументы среднего основывались на this.scores и this.lowest?   -  person Major Byte    schedule 10.05.2014
comment
Среднее значение необходимо обновлять при внесении изменений в scores и lowest.   -  person Jefftopia    schedule 10.05.2014


Ответы (1)


Вы действительно могли бы использовать вычисление для mean

this.mean = ko.computed(
    function() {
      var sum  = 0;
      var count = 0;
      var n = 0;
      for(n;n < _this.scores().length;n++)
      {
        var score = _this.scores()[n];
          if (_this.lowest.indexOf(score)<0) {
            sum += parseFloat(score());
            count++;
          }
      }

      if (count > 0) {
        sum = sum / count;
        return sum.toFixed(2);
      } else {
        return 'N/A';
      }
});

это сработает, когда вы добавите в lower(), scores() и change scores().

обязательный jsfiddle.

Обновление:
Забыл упомянуть, что я также изменил кое-что важное. Из исходного кода:

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 = ko.observableArray(tmp.splice((tmp.length-2),tmp.length-1));
    });
 };

помимо перемещения comparator за пределы функции dropLowestScores, я изменил строку:

student.lowest = ko.observableArray(tmp.splice((tmp.length-2),tmp.length-1));

to

student.lowest(tmp.splice((tmp.length-2),tmp.length-1));

student.lowest — это наблюдаемый массив, нет необходимости снова определять его как observableArray, фактически это нарушает вычисление mean. (Поправка на самые низкие баллы согласно моему предыдущему комментарию здесь не указана).

person Major Byte    schedule 09.05.2014
comment
Однако Drop Lowest Score в настоящее время теряет все баллы, кроме самого высокого. Увидим, я могу исправить это, а также. - person Major Byte; 10.05.2014
comment
Drop Lowest Score теперь тоже работает правильно - person Major Byte; 10.05.2014
comment
Некоторое время назад я пытался сделать это с помощью вычисляемого, стек сказал мне не делать этого. Я вижу, что это работает отлично, но теперь я еще больше не уверен, когда следует или не следует использовать ko.computed. - person Jefftopia; 10.05.2014
comment
@Jefftopia, не могли бы вы указать мне на вопрос / ответ, на который вы ссылаетесь? - person Major Byte; 11.05.2014