2016-12-23 3 views
1
function range(start, end) { 
    var acc = []; 
    for (var i = start; i < end; i++) { 
    acc.push(i); 
    } 
    return acc; 
} 

Используя функцию диапазона и метод уменьшения, мне нужно переписать факториальную функцию.Как написать факториальную функцию с уменьшением и диапазоном?

function factorial(n) { 
    // YOUR CODE HERE 
} 

Мне был дана подсказка, чтобы написать функцию в forEach сначала, а затем переписать ее с диапазоном и уменьшить. Это была моя попытка.

function factorial(n){ 
    var product = 1; 
    n.forEach(function(x){ 
    if(x===0){ 
     return 1;} 
    product *= factorial(x-1); 
    }); 
    return product; 
} 

factorial(4); 

Это была моя попытка. Я знаю, что это беспорядок, но мои вопросы: как я могу использовать forEach, когда n - это просто число, а forEach - для массивов? так как они хотят, чтобы я использовал каждый первый, чтобы написать факториальную функцию, мне нужно правильно использовать базовый регистр? Я также посмотрел в MDN и попытался понять сокращение, следуя их синтаксису с аккумулятором + currentValue и придумал этот псевдокод.

function factorial(n){ 
    n.reduce(function(x){ 
    x*range; 
    }); 
} 

factorial(5) 

еще раз Я не понимаю, как я могу использовать сокращение, если параметр не является массивом.

+0

я так потерял с этой проблемой .... – heliu

+0

в случае 'n.forEach',' n' должен быть массивом, так как [ 'Массив # forEach'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) - это метод, доступный только для массивов. –

+0

Я могу только предположить, что они действительно означали диапазон использования и сначала для первого, затем используйте диапазон и уменьшите.Это единственное, что имеет смысл для меня. Используйте диапазон для генерации чисел от 1 до n, затем используйте forEach для итерации по массиву, умножая окончательный ответ. Затем избавьтесь от forEach и используйте сокращение по результатам диапазона (n). forEach сам по числу просто не сработает. –

ответ

2

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

Мы можем выполнить первый шаг, используя предоставленный нам метод диапазона. Метод диапазона возвращает массив всех целочисленных значений между минимальным значением (включительно) и максимальным значением (исключительным). Например, если мы позвоним range(1,5), он вернет [1,2,3,4]. Когда мы хотим выполнить факториальную операцию, мы хотим умножить все предыдущие целочисленные значения , включая текущее значение. Чтобы получить массив из всех предыдущих значений и текущего значения, мы можем использовать

var factors = range(1,n+1); 

в начале нашей факториальной функции.

Теперь, когда у нас есть все наши факторы, мы можем использовать метод уменьшения, чтобы умножить их все вместе. Метод reduce будет выполнять предоставленную функцию по каждому значению массива по порядку. В этом случае мы хотим умножить все наши факторы вместе. Мы можем использовать

var multFactors = factors.reduce(function(a,b){ 
    return a*b; 
},1); 

Чтобы умножить каждое значение в массиве вместе. При использовании 1 в качестве второго параметра метода сокращения, мы гарантируем, что factorial(0) не вызовет каких-либо ошибок (спасибо @Eterm для заметив это)

Теперь все, что осталось вернуть multFactors.

Когда все это помещается вместе, вы в конечном итоге с этим

function range(start, end) { 
    var acc = []; 
    for (var i = start; i < end; i++) { 
    acc.push(i); 
    } 
    return acc; 
} 

function factorial(n) { 
    var factors = range(1,n+1); 
    var multFactors = factors.reduce(function(a,b){ 
    return a*b; 
    },1); 
    return multFactors; 
} 

Edit:

Если вы хотите, чтобы избежать ошибки с отрицательными факториалов, вы можете применить абсолютное значение функции к n.

Чтобы сделать это, мы можем изменить

var factors = range(1,n+1); 

в

var factors = range(1, Math.abs(n)+1); 

Принимая факториал отрицательного числа должно быть определено, однако с этой новой линии мы избежать ошибок, сделав номер положительны. Если вы хотите сохранить знак факториала, вы можете добавить эти строки после того, как вы установите multFactors, но перед тем, как вернуть его.

if(n < 0) 
    multFactors *= -1; 

Когда это будет сделано, вы в конечный итоге с этим (с комментариями сейчас, потому что она больше)

Надеется, что это помогает.

+1

factorial (0) возвращает ошибку здесь, поэтому потребуется специальная обработка. – Eterm

+1

Вы правы, хорошо поймайте. Это также проблема с отрицательными числами (хотя это может быть хорошей вещью, учитывая, что отрицательные факториалы не определены). Я сделал решение [здесь] (http://output.jsbin.com/cebasekasi), но я также отредактирую свой ответ, чтобы включить это. Спасибо. –

+0

Благодарим вас за подробное объяснение @MichaelRyan, я не думаю, что я получил бы это, я был все более оскорблен. – heliu

0

Вы говорите что-то, когда говорите forEach is for Arrays but n is a number. Таким образом, вам нужно построить массив, по которому вы будете циклически (и позже уменьшите).

var n = 10; 

var i = 0; 

//use your "range" function to define an array from 2 to end. 
var z = range(2, n + 1); 

//Now we have an array we can reduce with multiplication initializing the accumulator to 1. 
z.reduce(function(a,b){return a*b;}, 1); 

Функция внутри сокращения - это просто умножение, второй аргумент инициализирует аккумулятор.

Никакой специальной обработки не требуется 0 или 1 здесь, потому что массив построен будет пустым, и уменьшить просто вернуть начальное значение 1.

+0

Вы даже можете удалить начальное значение: 'z.reduce (function (a, b) {return a * b;})'. Используя функцию стрелки, она становится «z.reduce ((a, b) => a * b)». ;-) – RobG

+1

На самом деле вы не можете, если вы попробуете n = 1, вы получите следующую ошибку: «Исключение: ТипError: уменьшение пустого массива без начального значения» – Eterm

+0

Только в том случае, если в массиве нет элементов, см. [* Array.prototype.reduce *] (http://ecma-international.org/ecma-262/7.0/index.html#sec-array.prototype.reduce). – RobG

0

Вы можете использовать Array. apply и создать инклюзивный диапазон для заданных начальных и конечных значений.

Затем уменьшить с умножением.

function range(start, end) { 
 
    return Array.apply(null, { length: end - start + 1 }).map(function (_, i) { return start + i; }); 
 
} 
 

 
function multiply(a, b) { return a * b; } 
 

 

 
var array = range(3, 7), 
 
    product = array.reduce(multiply); 
 

 
console.log(array); 
 
console.log(product); 
 
console.log(range(1, 10).reduce(multiply));
.as-console-wrapper { max-height: 100% !important; top: 0; }

0

Просто Array.prototype.reduce() вы можете сделать следующее;

function factorial(a){ 
 
return Array(a[1]-a[0]).fill() 
 
         .reduce((r,_,i) => r *= a[0]+i+1, a[0] ? a[0] : 1); 
 
} 
 

 
console.log(factorial([0,10])); 
 
console.log(factorial([2,5]));

0

Там множество других ответов здесь, которые предлагают практический подход к решению проблемы. Мой ответ вместо этого целенаправленно непрактичен (как написано на JavaScript), но направлен на то, чтобы научить вас другим.

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

Сначала мы определяем Y-комбинатор, затем реализуем range и reduce с использованием Y. Затем мы можем, наконец, реализовать factorial.

const U = f => f (f) 
 

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

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

 
const reduce = Y (h => f => acc => ([x, ...xs]) => 
 
    (x === undefined) 
 
    ? acc 
 
    : h (f) (f (acc) (x)) (xs) 
 
) 
 
    
 
const mult = x => y => y * x 
 

 
const factorial = x => 
 
    reduce (mult) (1) (range (1) (x)) 
 
    
 
console.log(factorial (5)) // 120 
 
console.log(factorial (6)) // 720 
 
console.log(factorial (7)) // 5040

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