Я перевожу проект с Python на Node.js - до этого момента все шло хорошо. У меня есть функция, которая должна конвертировать количество опыта у кого-то в уровень. Я попытался переписать рабочую функцию из Python в Node.js, но функции возвращают совершенно разные ответы, и я не могу понять, почему.

Python :

def calculateLevel(exp):
    if exp < 83: return 1
    else:
        calcExp = 0
        for level in range(1, 1000):
            diff = int(level + 300 * math.pow(2, float(level)/7))
            calcExp += diff
            if exp < calcExp//4:
                break
        return level

Node.js:

const _ = require("underscore");
// ...
function calculateLevel(exp) {
    return new Promise((resolve, reject) => {
        if (exp < 83) resolve(1);
        else {
            var calcExp = 0;
            for (var i in _.range(1, 1000)) {
                calcExp += parseInt(i + 300 * Math.pow(2, i/7));
                if (exp < Math.floor(calcExp/4)) {
                    resolve(i);
                    break;
                }
            }
        }
    });
}

Например, calculateLevel(123456) в Python возвращает 51 (правильный ответ), но await calculateLevel(123456); в Node.js возвращает 15 (неправильный ответ).

Очевидно, что в версии Node.js что-то не так, но я не могу понять, что это такое.

Любая помощь приветствуется. Заранее спасибо.

0
L. Thompson 21 Авг 2018 в 18:00

4 ответа

Лучший ответ

В Python:

for i in range(1, 10)
   print(i)

Создаст последовательность для 1 2 3 4 5 6 7 8 9

for...in в JavaScript будет перебирать ключи, а не значения.

Так что for (var i in _.range(1, 1000)) { всегда будет 0 ... 999

Измените его на for...of

function calculateLevel(exp) {
    return new Promise((resolve, reject) => {
        if (exp < 83) resolve(1);
        else {
            var calcExp = 0;
            for (var i of _.range(1, 999)) {
                calcExp += parseInt(i + 300 * Math.pow(2, i/7));
                if (exp < Math.floor(calcExp/4)) {
                    resolve(i);
                    break;
                }
            }
        }
    });
}

Кроме того, неясно, почему вы используете Promise здесь, потому что у вас нет асинхронного кода здесь. Таким образом, вы можете полностью удалить Обещание здесь.

const _ = require("underscore");
// ...
function calculateLevel(exp) {
  if (exp < 83) return 1;
  else {
      var calcExp = 0;
      for (var i of _.range(1, 1000)) {
          calcExp += parseInt(i + 300 * Math.pow(2, i/7));
          if (exp < Math.floor(calcExp/4)) {
              break;
          }
      }
      return i;
  }
}

console.log(calculateLevel(123456))
2
t.niese 21 Авг 2018 в 15:17

Просто добавлю свое мнение, так как у вас уже есть принятый ответ.

Хотя вы конвертируете блок кода Python в Javascript, я чувствую, что вам не обязательно использовать тот же синтаксис и имена методов.

Например, если мы возьмем следующий блок кода в Python и JS;

Python :

def calculateLevel(exp):
    if exp < 83: return 1
    else:
        calcExp = 0
        for level in range(1, 1000):
            diff = int(level + 300 * math.pow(2, float(level)/7))
            calcExp += diff
            if exp < calcExp//4:
                break
        return level

Примечание: здесь используется for level in range(1, 1000):.

То же самое можно сделать с помощью цикла while. Так что это может выглядеть примерно так:

level = 0
while level <= 1000:
    diff = int(level + 300 * math.pow(2, float(level)/7))
    calcExp += diff
    if exp < calcExp//4:
        break
return level

Но зацикливание на for in range() в Python более эффективно, чем использование while. Если бы я запустил простой тест, я увидел бы следующие результаты.

for in range(): 55 вызовов функций за 0,000 секунд

while: 1650 вызовов функций за 0,001 секунды

Хотя в случае с Python это так, в Javascript все обстоит иначе (и в вашем подходе, где используется функция подчеркивания range()). Хотя имена функций выглядят одинаково, это не означает, что они имеют такую же производительность, как в Python.

Фактически, цикл по _.range() намного медленнее, чем цикл по while. Если вы посмотрите на некоторые результаты тестов, вы увидите что-то вроде этого:

Using _.range(1, 1000): на 67,67% медленнее

https://jsbench.me/b2jl4vvgnw/1

Итак, со всем этим, я думаю, что лучше написать это, используя цикл while, и с небольшой модификацией я бы написал это так:

function calculateLevel(exp) {
    var level = 1;

    if (exp > 83){
        var calcExp = 0;
        while(level <= 1000){
            calcExp += parseInt(level + 300 * Math.pow(2, level/7));
            if (exp < Math.floor(calcExp/4))
                break;
            level++;
        }
    }
    return level;
}

Надеюсь, это поможет!!

0
Nimeshka Srimal 22 Авг 2018 в 08:40
if (exp < Math.floor(calcExp/4)) {
                    resolve(i);
                    break;
                }

Должно быть

if (exp < Math.floor(calcExp/4)) {
                        break;
                    }
resolve(i)
0
Prodigle 21 Авг 2018 в 15:04

Я запустил этот код:

function calculateLevel(exp) {
    return new Promise((resolve, reject) => {
        if (exp < 83) resolve(1);
        else {
            var calcExp = 0;
            for (var i=1; i<1000; i++) {
                calcExp += parseInt(i + 300 * Math.pow(2, i/7));
                if (exp < Math.floor(calcExp/4)) {
                    resolve(i);
                    break;
                }
            }
        }
    }); }

console.log(calculateLevel(123456));

И он вернулся 51.

Что-то еще, вероятно, вызывает проблему.

0
Sean Dvir 21 Авг 2018 в 15:09
51951533