루비에서 숫자 배열을 합산하는 방법?


563

정수 배열이 있습니다.

예를 들면 다음과 같습니다.

array = [123,321,12389]

그것들의 합계를 얻는 좋은 방법이 있습니까?

알아요

sum = 0
array.each { |a| sum+=a }

작동 할 것이다.


19
제발 참고 루비 2.4+ 가지고array.sum
— 임마

루비 2.6에는 없습니다. 루비는주고, 루비는 빼앗아갑니다.
— Lori

1
@Lori 흠? 링크
— steenslag

죄송합니다. 그 당시 나는 rbenv가 미끄러 져서 2.6을 사용하고 있다고 잘못 생각했습니다.
— Lori

답변:


612

이 시도:

array.inject(0){|sum,x| sum + x }

루비의 열거 가능한 문서를보십시오

(참고 : 0기본 사례는 필요하기 때문에 0빈 배열에 대신 반환됩니다 nil)


317
jorney 's array.inject(:+)가 더 효율적입니다.
— Peter

3
array.inject(:+)Ruby 1.8.6에서 문제 를 일으키는 것 같습니다. 예외 "LocalJumpError : no block given"이 나타날 수 있습니다.
— Kamil Szot

34
레일 array.sum에서 배열 값의 합계를 제공 할 수 있습니다.
— Kamil Szot

32
대부분의 경우 (에서와 같이 ) reduce의 별칭 인 을 사용하는 것을 선호합니다 . injectarray.reduce( :+ )
— Boris Stitnicky

3
@Boris 또한 Rubycop은 inject대신 사용에 대해 경고합니다 reduce.
— Droogans

810

또는 Ruby 1.9 방식으로 시도하십시오.

array.inject(0, :+)

참고 : 0기본 사례가 필요 nil하면 빈 배열에 반환됩니다.

> [].inject(:+)
nil
> [].inject(0, :+)
0

6
이 방법을 사용하여 객체의 속성을 합산하는 방법은 무엇입니까? 내 배열 [product1, product2] product1.price + product2.price를 합산하려고합니다. array.inject (: +)를 사용할 수 있습니까?
— Pablo Cantero

7
array.map (: : : 가격) .inject (+) 당신은 유사한지도 방법 트릭 사용할 수 있습니다
— markquezada

100
array.map(&:price).inject(0, :+)조금 더 안전합니다. 빈 목록이 있으면 nil 대신 0 을 얻습니다 .
— johnf

11
array.map (...). inject (...) 사용하면 비효율적이며 모든 데이터를 두 번 반복합니다. 시도 array.inject(0) { |sum, product| sum += product.price }
— everett1992

4
@ everett1992와 결과적으로 최적화조차도 이루어지지 않았습니다. 두 단계로 수행하는 것이 일관되게 더 빠릅니다. gist.github.com/cameron-martin/b907ec43a9d8b9303bdc
— Cameron Martin

290
array.reduce(0, :+)

반면에 Reducearray.inject(0, :+) 라는 용어 는 MapReduce 프로그래밍 모델 의 등장과 함께보다 일반적인 용어가되었습니다 .

주입 , 축소 , 접기 , 누적 및 압축 은 모두 접기 기능 클래스와 동의어 입니다. 코드 기반에서 일관성이 가장 중요하지만 다양한 커뮤니티가 한 단어를 다른 단어보다 선호하는 경향이 있기 때문에 대안을 아는 것이 유용합니다.

map-reduce ververage를 강조하기 위해, 그 배열에서 끝나는 것을 조금 더 용서하는 버전이 있습니다.

array.map(&:to_i).reduce(0, :+)

추가적인 관련 자료 :


11
동의 reduce합니다. 기능의 기능에 대해 더 inject많이 말하지만 훨씬 더 시원하게 들립니다.
— everett1992

1
마지막 의견에 동의하면 나에게 최고의 답변을 주었다.
— Jerska

1
내가 만드는 것이 한 의견은 것입니다 reduce및 map고차 함수는 맵리 듀스 앞선한다. 영감은 다른 방식으로 진행됩니다. 그리고 MapReduce의 의미에서 이는 단순한 기능적 감소와는 약간 다른 작동으로, 다른 기계가 통신하는 방식에 영향을 미칩니다.
— acjay

Ken Iverson은 프로그래밍 언어 APL에서 "환원 연산자"라는 연산자를 소개했습니다. 출처 : 아이버슨, 케네스. 1962. 프로그래밍 언어. 와일리 또 다른 출처 : "사고의 도구로서의 표기법", 1979 ACM Turing Award 강의, Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
— Fernando Pelliccioni

112

Rails가 설치되어있는 경우 (비교를 위해) (실제로는 ActiveSupport 만) :

require 'activesupport'
array.sum

12
최신 버전의 activesupport는 실제로 기본적으로 모든 확장을로드하지 않습니다. sum 모듈 : 만 require 'active_support/core_ext/enumerable.rb'필요하거나 모든 활성 지원이 필요합니다 : require 'active_support/all'. 자세한 내용은 여기 : API Docs
— dcashman

2
그 신경 쓰지 activesupportA는 대규모 로 이동하는 프로젝트에 드래그에 의존 array.inject(:+)하는가 array.sum.
— meagar

1
그렇지 않으면 좋은 언급 require 'active_support/core_ext/enumerable'을합니다. .rb접미사 가 없어야합니다 . 암시 적으로 추가되기 때문입니다.
— Per Lundberg

72

Ruby> = 2.4.0의 경우 sumEnumerables에서 사용할 수 있습니다 .

[1, 2, 3, 4].sum

기본 클래스를 mokeypatch하는 것은 위험합니다. 위험을 좋아하고 이전 버전의 Ruby를 사용하는 #sum경우 Array클래스에 추가 할 수 있습니다 .

class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end

1
이 작업을 수행하지 마십시오
— user3467349

왜 그런가요?
— YoTengoUnLCD

15
Monkeypatching 기본 클래스는 좋지 않습니다.
— user3467349

1
그가하고 싶은 요점은 Ruby> = 2.4 용 Monkey Patch를 수행 할 필요가없고, 원숭이 패치는 위험하며, 이제 열거 형을 기본적으로 합산 할 수 있지만 기능을 백 포트하는 방법도 있다는 것입니다.
— 피터 H. 볼링

빈 배열에서 구현이 nil을 반환하기 때문에 다운 보트되었습니다.
— Eldritch Conundrum

45

Ruby 2.4.0의 새로운 기능

적절하게 이름이 지정된 method를 사용할 수 있습니다 Enumerable#sum. 그것은 많은 장점이 있습니다inject(:+) 있지만 마지막에 읽을 중요한 메모가 있습니다.

예

범위

(1..100).sum
#=> 5050

배열

[1, 2, 4, 9, 2, 3].sum
#=> 21

[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7

중요 사항

이 방법은와 동일하지 않습니다 #inject(:+). 예를 들어

%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer

또한,

(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)

왜 이런지에 대한 자세한 내용 은 이 답변 을 참조하십시오 sum.


19

다양성을 위해 배열이 숫자 배열이 아니라 숫자 (예 : 양) 속성을 가진 객체 배열 인 경우 에도이 작업을 수행 할 수 있습니다.

array.inject(0){|sum,x| sum + x.amount}

3
이것은 다음을 수행하는 것과 같습니다 array.map(&:amount).inject(0, :+). 다른 답변을 참조하십시오.
— Richard Jones

4
어떤 식 으로든 그렇습니다. 그러나 map그런 다음 사용 inject하려면 배열을 두 번 반복해야합니다. 한 번은 새 배열을 작성하고 한 번은 멤버를 합산합니다. 이 방법은 약간 더 장황하지만 더 효율적입니다.
— HashFail

분명히 더 효율적이지 않습니다. gist.github.com/cameron-martin/b907ec43a9d8b9303bdc- 이 답변의 의견에 대한 답변 : stackoverflow.com/a/1538949/1028679
— rmcsharry

19

루비 2.4 이상 / 레일- array.sum즉[1, 2, 3].sum # => 6

루비 프리 2.4- array.inject(:+)또는array.reduce(:+)

* 참고 :이 #sum방법은 2.4에 새로 추가 enumerable되었으므로 이제 array.sumRails뿐만 아니라 순수한 루비에서도 사용할 수 있습니다 .


2
이 기능이 포함 된 Ruby 2.4.0이 오늘 릴리스되었습니다! 🎉
— amoebe

@amoebe 당신이 맞습니다! 이 유용한 기능이 포함되어있어 기쁩니다.
— 수집

18

루비 1.8.7 방법은 다음과 같습니다.

array.inject(0, &:+) 

2011 년 코멘트를 읽고 1.8.6을 사용할 때 여전히 관련이 있다면 업그레이드하십시오!
— Andrew Grimm 2016 년

16

간단하게 사용할 수 있습니다 :

    example = [1,2,3]
    example.inject(:+)

왜 이것이 효과 inject(:+)가 inject :+있습니까?
— Arnold Roa

@ArnoldRoa "inject : +"는 저에게 효과적입니다. 어떤 결과를 얻었습니까?
— Ganesh Sagare


5

Ruby 2.4.0이 릴리스되었으며 Enumerable # sum 메소드가 있습니다. 그래서 당신은 할 수 있습니다

array.sum

문서의 예 :

{ 1 => 10, 2 => 20 }.sum {|k, v| k * v }  #=> 50
(1..10).sum                               #=> 55
(1..10).sum {|v| v * 2 }                  #=> 110

3

또한 다음을 허용합니다 [1,2].sum{|x| x * 2 } == 6.

# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
class Array
  def sum(method = nil, &block)
    if block_given?
      raise ArgumentError, "You cannot pass a block and a method!" if method
      inject(0) { |sum, i| sum + yield(i) }
    elsif method
      inject(0) { |sum, i| sum + i.send(method) }
    else
      inject(0) { |sum, i| sum + i }
    end
  end
end

3

값이 0이 아닌 배열의 경우 압축을 수행 한 다음 합계를 주입 할 수 있습니다

a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)

2
array.reduce(:+)

Ranges 에서도 작동합니다 .

(1..10).reduce(:+) returns 55

1

골프를 느끼면 할 수 있습니다

eval([123,321,12389]*?+)

문자열 "123 + 321 + 12389"를 만든 다음 eval 함수를 사용하여 합계를 수행합니다. 이것은 골프 목적 으로 만 사용되므로 올바른 코드로 사용해서는 안됩니다.


1

방법 1 :

    [1] pry(main)> [1,2,3,4].sum
    => 10
    [2] pry(main)> [].sum
    => 0
    [3] pry(main)> [1,2,3,5,nil].sum
    TypeError: nil can't be coerced into Integer

방법 2 :

   [24] pry(main)> [].inject(:+)
   => nil
   [25] pry(main)> [].inject(0, :+)
   => 0
   [4] pry(main)> [1,2,3,4,5].inject(0, :+)
   => 15
   [5] pry(main)> [1,2,3,4,nil].inject(0, :+)
   TypeError: nil can't be coerced into Integer
   from (pry):5:in `+'

방법 3 :

   [6] pry(main)> [1,2,3].reduce(:+)
   => 6
   [9] pry(main)> [].reduce(:+)
   => nil
   [7] pry(main)> [1,2,nil].reduce(:+)
   TypeError: nil can't be coerced into Integer
   from (pry):7:in `+'

방법 4 : Array에 nil 및 empty 값이 포함 된 경우 위의 함수를 사용하면 기본적으로 reduce, sum,

TypeError : nil을 정수로 강제 변환 할 수 없습니다

이것을 극복하면

   [16] pry(main)> sum = 0 
   => 0
   [17] pry(main)> [1,2,3,4,nil, ''].each{|a| sum+= a.to_i }
   => [1, 2, 3, 4, nil, ""]
   [18] pry(main)> sum
   => 10

방법 6 : 평가

문자열에서 Ruby 표현식을 평가합니다.

  [26] pry(main)> a = [1,3,4,5]
  => [1, 3, 4, 5]
  [27] pry(main)> eval a.join '+'
  => 13
  [30] pry(main)> a = [1,3,4,5, nil]
  => [1, 3, 4, 5, nil]
  [31] pry(main)> eval a.join '+'
  SyntaxError: (eval):1: syntax error, unexpected end-of-input
  1+3+4+5+

1

배열의 합을 할 수있는 3 가지 방법

1) array.inject(0){|sum,x| sum + x }

2) array.inject('+')

삼) array.join('+')


0

또는이 방법을 시도 할 수 있습니다 :

def sum arr
  0 if arr.empty
  arr.inject :+
end


0
number = [1..100]

number. each do |n|

    final_number = n.sum

    puts "The sum is #{final_number}"
end

* 이것은 새로운 개발자로서 저에게 효과적이었습니다. [] 내의 값을 변경하여 숫자 범위를 조정할 수 있습니다



당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.