2016-06-01 7 views
5

Привет, ребята, я пытаюсь создать функцию в javascript, которая возвращает массив из диапазона (начало, конец), а им предполагается сделать необязательный аргумент, который по умолчанию равен одному, когда он не определен. Я могу заставить эту функцию работать, когда я предоставляю все аргументы, но возвращает пустой массив, когда я передаю только два аргумента. Возникает вопрос:Создание функции диапазона в javascript

Напишите функцию диапазона, которая принимает два аргумента, начало и конец, и возвращает массив, содержащий все числа от начала до конца (и включая).

Затем напишите функцию суммы, которая принимает массив чисел и возвращает сумму этих чисел. Запустите предыдущую программу и посмотрите, действительно ли она возвращается 55.

В качестве назначения бонуса измените функцию диапазона, чтобы принять дополнительный третий аргумент, который указывает значение «шаг», используемое для создания массива. Если ни один шаг не задан, элементы массива увеличиваются с шагом в 1, что соответствует старому поведению. Диапазон вызова функции (1, 10, 2) должен возвращать [1, 3, 5, 7, 9]. Убедитесь, что он также работает с отрицательными значениями шага, так что диапазон (5, 2, -1) создает [5, 4, 3, 2].

и вот мой код

function range(start, end, increment){ 
var array = []; 
var current = start; 
var counter; 
if (increment == undefined){ 
    counter = 1; 
} 

else { 
    counter = increment; 
} 

if (increment > 0){ 
    while(current <= end){ 
     array.push(current); 
     current += counter; 
    } 
} 

else if (increment < 0){ 
    while(current >= end){ 
     array.push(current); 
     current += counter; 

    } 
} 

return array; 
} 

может кто-нибудь объяснить, почему его отключающей? я знаю, некоторые C# и им используется, чтобы быть в состоянии перейти в отладчике в визуальной студии, когда что-то идет не так, в отличие от Javascript

+1

У JS есть много отладчика. Один из них в Chrome, вероятно, лучший. Откройте его, вы сможете пройти через код. –

+0

Общий JS-idiom для *, если он не определен, будет вместо этого: * var counter = increment || 1; ' – 4castle

+0

@ 4castle вы могли бы объяснить дальше? не совсем уверен, как это работает. было бы лучше использовать оператор '?'? – Nate

ответ

3

Сначала проверить, если increment не определено и установлено counter соответственно, но позже вы проверяете if (increment > 0){ снова. Пока это undefined Ни один из ваших случаев не подходит, поэтому ничего не происходит.

Измените ваши чеки на это:

if (counter > 0){ 
    // ... 
} 
else if (counter < 0){ 
    // ... 
} 
4

Вы могли бы упростить код немного и использовать переменную increment для приращения. Но прежде, я предлагаю проверить, является ли значение ложным (0, null, undefined и т. Д.) И назначить ему 1.

Не реализовано: проверьте, подходит ли start и end.

function range(start, end, increment) { 
 
    var array = []; 
 
    var current = start; 
 

 
    increment = increment || 1; 
 
    if (increment > 0) { 
 
     while (current <= end) { 
 
      array.push(current); 
 
      current += increment; 
 
     } 
 
    } else { 
 
     while (current >= end) { 
 
      array.push(current); 
 
      current += increment; 
 
     } 
 
    } 
 
    return array; 
 
} 
 

 
console.log(range(1, 3, 0));  
 
console.log(range(2, 5)); 
 
console.log(range(1, 9, 1)); 
 
console.log(range(5, 2, -1));

+1

Это хорошо, потому что он также предотвращает бесконечный цикл, когда третий параметр равен «0». – 4castle

+1

@ 4castle Я бы сказал иначе. Это не цель утилиты, чтобы спасти вас от себя. Ничто не мешает вам помещать 'do',' for' или 'while' в бесконечный цикл. Почему функции, которые мы пишем, должны быть разными? Я действительно предпочитаю API с жесткими краями. Я чувствую поведение, которое мы не указывали, должно быть * undefined *. См. Мой ответ для уточнения моей точки зрения. – naomik

+0

@NinaScholz, все это в сторону, это в противном случае очень хороший ответ^_^ – naomik

0

Данные ответы велики.Я просто хотел, чтобы дать вам представление о том, как более функциональный подход мог бы решить задачу:

// auxiliary functions: 
const append = (x, xs) => xs.concat([x]); 
const prepend = (x, xs) => [x].concat(xs); 

// main function 
const range = (x, y, step, acc = [], op = append) => 
step && step < 0 
    ? range(y, x, -step, acc, prepend) 
    : step && x <= y 
    ? range(x + step, y, step, op(x, acc), op) // tail call 
    : acc; 

console.log(range(1,5,1)); // [1,2,3,4,5] 
console.log(range(1,5,2)); // [1,3,5] 
console.log(range(1,5,6)); // [1] 
console.log(range(5,1,1)); // [] 
console.log(range(1,5,0)); // [] 
console.log(range(5,1,-1)); // [5,4,3,2,1] 
console.log(range(5,1,-2)); // [5,3,1] 
console.log(range(5,1,-6)); // [1] 
console.log(range(1,5,-1)); // [] 

Алгоритм:

  • acc = [] и op = append значения параметров по умолчанию (принимаются, если опущено во время вызова функции)
  • step && step < 0 короткого замыкания, если step равен нулю, в противном случае проверка, если шаг является отрицательным
  • range(y, x, -step, acc, prepend) вызывается, когда step отрицателен и преобразует параметризацию range «сек, так что step может быть положительным (обратите внимание, что -step эквивалентен -(-1), который оценивается в 1)
  • range(x + step, y, step, op(x, acc), op) рекурсивный случай, значит, функция вызывает себя (обратите внимание, что op может быть либо append или prepend в зависимости от исходного знака step, что x увеличивается на step и приложенный/предваряется acc)
  • acc базового случай, который останавливает рекурсию и возвращает накопленный массив
2

Очень простой однонаправленного (по возрастанию), включая диапазон - идет от x к y увеличивается на 1 каждый раз.

// range :: (Int, Int) -> [Int] 
 
const range = (x,y) => 
 
    x > y ? [] : [x, ...range(x + 1, y)]; 
 

 
console.log(range(1,4)); // [1,2,3,4] 
 
console.log(range(3,3)); // [3] 
 
console.log(range(6,3)); // []

Небольшое приспособление, которое поддерживает двунаправленную (по возрастанию или по убыванию) Диапазон - по-прежнему увеличивается или уменьшается с помощью 1

// range :: (Int, Int) -> [Int] 
 
const range = (x,y) => { 
 
    if (x > y) 
 
    return range(y,x).reverse(); 
 
    else 
 
    return x === y ? [y] : [x, ...range(x + 1, y)]; 
 
} 
 

 
console.log(range(1,4)); // [1,2,3,4] 
 
console.log(range(3,3)); // [3] 
 
console.log(range(6,3)); // [6,5,4,3]

Еще одна адаптация, которая использует функции более высокого порядка для большего контроля над диапазоном - это эффективно дает вам степенное/приращение поведения, которое некоторые из вас ищут - это более эффективно, поскольку оно позволяет вам использовать функцию t, чтобы выбрать следующее значение.

const gte = x => y => y >= x; 
 
const lte = x => y => y <= x; 
 
const add = x => y => y + x; 
 
const sub = x => y => y - x; 
 

 
// range :: (Int, (Int -> Bool), (Int -> Int)) -> [Int] 
 
const range = (x, p, t) => { 
 
    if (p(x)) 
 
    return [x, ...range(t(x), p, t)]; 
 
    else 
 
    return []; 
 
}; 
 

 
console.log(range(2, lte(8), add(2))); // [2,4,6,8] 
 
console.log(range(9, gte(0), sub(3))); // [9,6,3,0] 
 
console.log(range(9, gte(0), sub(5))); // [9, 4] 
 

 
// very power. wow. 
 
const double = x => x + x; 
 
console.log(range(2, lte(50), double)); // [2,4,8,16,32]

Эта функция имеет те же риски, связанные с for и while - это до вас, чтобы убедиться, что вы не поставить его в бесконечный цикл.


функциональная перегрузка

Предупреждение: Эзотерические, непрактичные функционалы вперед. Следующая информация предоставляется только для вашего академического удовольствия.

range функция также происходит с одним из моих любимых демонстраций Y комбинатора. Здесь я покажу вам два примера.

наивным range

const U = f => f (f); 
 
const Y = U (h => f => f (x => h (h) (f) (x))); 
 

 
const range = Y (f => acc => x => y => 
 
    x > y ? acc : f ([...acc, x]) (x + 1) (y) 
 
) ([]); 
 

 
console.log(range (3) (6)); // [3,4,5,6] 
 
console.log(range (6) (6)); // [6] 
 
console.log(range (9) (6)); // []

и высшего порядка range

const U = f => f (f); 
 
const Y = U (h => f => f (x => h (h) (f) (x))); 
 

 
const lt = x => y => y < x; 
 
const gt = x => y => y > x; 
 
const add1 = x => x + 1; 
 
const sub1 = x => x - 1; 
 

 
const range = Y (f => acc => x => p => t => 
 
    p(x) ? f ([...acc, x]) (t(x)) (p) (t) : acc 
 
) ([]); 
 

 
console.log(range (3) (lt(6)) (add1)); // [3,4,5] 
 
console.log(range (6) (lt(6)) (add1)); // [] 
 
console.log(range (9) (gt(6)) (sub1)); // [9,8,7]

Какая красота.

Смежные вопросы