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


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
내가 만드는 것이 한 의견은 것입니다 reducemap고차 함수는 맵리 듀스 앞선한다. 영감은 다른 방식으로 진행됩니다. 그리고 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.