Как найти сумму факториалов - PullRequest
2 голосов
/ 15 января 2020

Используя minitest, я пытаюсь выполнить этот тест, который запрашивает сумму 5!:

def test_sum_of_factorials

  sum_of_factorials = 0
  numbers = [1, 2, 3, 4, 5]


  assert_equal 153, sum_of_factorials
end

Я написал решение, но оно длинное и повторяющееся:

fractorial_5 = numbers.inject(1) {|aggregate, num| aggregate * num}
fractorial_4 = numbers[0..3].inject(1) {|aggregate, num| aggregate * num}
fractorial_3 = numbers[0..2].inject(1) {|aggregate, num| aggregate * num}
fractorial_2 = numbers[0..1].inject(1) {|aggregate, num| aggregate * num}
fractorial_1 = 1

fractorials_array = [fractorial_1, fractorial_2, fractorial_3, fractorial_4, fractorial_5]

fractorials_array.each {|fractorial| sum_of_factorials += fractorial}

Есть ли у кого-нибудь более чистое и простое решение, которое он хотел бы объяснить?

Ответы [ 5 ]

1 голос
/ 16 января 2020

Я хотел бы просто, как показано ниже,

[1, 2, 3, 4, 5].map { |x| (1..x).inject(1, :*) }.sum
# => 153
1 голос
/ 16 января 2020

Другим вариантом является определение факториальной функции (украденной здесь: { ссылка }), возможно, в качестве патча для класса Integer:

module MyMathFunctions
  def factorial
    (1..self).reduce(1, :*)
  end
end

Integer.include MyMathFunctions

Так что вы можете использовать это так: 10.factorial #=> 3628800

Затем просто позвоните:

[1, 2, 3, 4, 5].sum &:factorial
#=> 153
1 голос
/ 15 января 2020

Похоже, вам дано:

def test_sum_of_factorials
  sum_of_factorials = 0
  numbers = [1, 2, 3, 4, 5]
  <...missing bits...>
  assert_equal 153, sum_of_factorials
end

и вас просят заполнить пропущенные биты . Я думаю, что-то вроде следующего запрашивается.

def test_sum_of_factorials
  sum_of_factorials = 0
  numbers = [1, 2, 3, 4, 5]
  fac = 1
  numbers.each do |n|
    fac *= n
    sum_of_factorials += fac
  end
  assert_equal 153, sum_of_factorials
end

Вместо этого мы можем написать это как:

def test_sum_of_factorials
  numbers = [1, 2, 3, 4, 5]      
  assert_equal 153, sum_of_factorials(numbers)
end

def sum_of_factorials(numbers)
  fac_sum = 0
  fac = 1
  numbers.each do |n|
    fac *= n
    fac_sum += fac
  end
  fac_sum
end

где

sum_of_factorials([1,2,3,4,5])
  #=> 153

Это было бы больше Ruby -подобно, однако, использовать Array # sum для записи sum_of_factorials следующим образом:

def sum_of_factorials(numbers)
  fac = 1
  numbers.sum { |n| fac *= n }
end

Вместе с названием вашего вопроса, именно поэтому авторы другие ответы предполагают, что вы спрашиваете, как улучшить метод sum_of_factorials. Во-первых, ему может быть передан аргумент numbers.max, а не массив numbers.

. Другой способ записи sum_of_factorials состоит в использовании метода Enumerator :: производить, который дебютировал в v2.7.

def sum_of_factorials(n)
  enum = Enumerator.produce([1,1]) { |n0, n1| [n0+1, (n0+1)*n1] }
  n.times.sum { enum.next.last }
end

(1..8).each { |n| puts "%d: %6d" % [n, sum_of_factorials(n)] }
1:      1
2:      3
3:      9
4:     33
5:    153
6:    873
7:   5913
8:  46233

Обратите внимание, что если:

enum = Enumerator.produce([1,1]) { |n0, n1| [n0+1, (n0+1)*n1] }
  #=> #<Enumerator: #<Enumerator::Producer:0x000059d490c742a0>:each> 

, то

enum.next #=> [1, 1] 
enum.next #=> [2, 2] 
enum.next #=> [3, 6] 
enum.next #=> [4, 24] 

, поэтому факториалы от 1 до 4 задаются (после переопределения или перемотки enum):

enum.next.last #=>  1 
enum.next.last #=>  2 
enum.next.last #=>  6 
enum.next.last #=> 24 

Если n может равняться нулю, добавьте строку return 1 if n.zero? в начале метода.

1 голос
/ 15 января 2020
def sum_of_factorials(n)
  (1..n).reduce([1, 0]) { |(f, sum), e| [(f *= e), (sum + f)] }.last
end

производит

sum_of_factorials(5) #=> 153

Объяснение:

def sum_of_factorials(n)
  (1..n).             # n times
    reduce([1, 0]) do # iterate and use [factorial, sum] as an accumulator
    |(f, sum), e|     # splat the accumulator into f and sum variables
      [               # each time recalculate the accumulator as
        f *= e,       # product of the element and previous factorial,
        sum + f       # sum of current factorial and previous sum
      ]
    end.last          # and return only last part(sum) of the accumulator
end
0 голосов
/ 15 января 2020

Поскольку вы можете написать 5! +4! +3! +2! +1 !, обычно 1! +2! +3! + ... + n! как 1 + 2 (1 + 3 (1 + 4 (1 + 5 (1 + ... (1 + n)))))), вы можете сделать это в O (n)

sum_of_factorials = 1
numbers.drop(1).reverse_each { |i| sum_of_factorials = 1 + i * sum_of_factorials }
...