programing

Ruby에서 map(&:method) 구문에 인수를 제공할 수 있습니까?

i4 2023. 5. 31. 15:17
반응형

Ruby에서 map(&:method) 구문에 인수를 제공할 수 있습니까?

당신은 아마 다음과 같은 루비 속기에 익숙할 것입니다.a배열임):

a.map(&:method)

예를 들어 irb에서 다음을 시도합니다.

>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]

구문a.map(&:class)의 줄임말입니다.a.map {|x| x.class}.

이 구문에 대한 자세한 내용은 "Ruby에서 map(&:name)은 무엇을 의미합니까?"에서 확인하십시오.

구문을 통해&:class당신은 메소드 콜을 하고 있습니다.class각 배열 요소에 대해.

제 질문은: 메소드 호출에 인수를 제공할 수 있습니까?만약 그렇다면, 어떻게?

예를 들어, 다음 구문을 변환하는 방법

a = [1,3,5,7,9]
a.map {|x| x + 2}

에게&:구문?

나는 그것을 제안하는 것이 아닙니다.&:구문이 더 좋습니다.저는 단지 사용하는 기계에 관심이 있을 뿐입니다.&:인수가 있는 구문입니다.

당신도 알고 있을 겁니다.+정수 클래스의 메서드입니다.irb에서 다음을 시도할 수 있습니다.

>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2

다음에 간단한 패치를 생성할 수 있습니다.Symbol다음과 같이:

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

이를 통해 다음과 같은 작업을 수행할 수 있습니다.

a = [1,3,5,7,9]
a.map(&:+.with(2))
# => [3, 5, 7, 9, 11] 

하지만 여러 매개 변수를 전달하는 것과 같은 다른 멋진 일들도 많이 있습니다.

arr = ["abc", "babc", "great", "fruit"]
arr.map(&:center.with(20, '*'))
# => ["********abc*********", "********babc********", "*******great********", "*******fruit********"]
arr.map(&:[].with(1, 3))
# => ["bc", "abc", "rea", "rui"]
arr.map(&:[].with(/a(.*)/))
# => ["abc", "abc", "at", nil] 
arr.map(&:[].with(/a(.*)/, 1))
# => ["bc", "bc", "t", nil] 

그리고 함께 작업하기도 합니다.inject두 개의 인수를 블록에 전달합니다.

%w(abecd ab cd).inject(&:gsub.with('cde'))
# => "cdeeecde" 

또는 [짧은 손] 블록을 속기 블록으로 전달하는 것과 같은 매우 멋진 것:

[['0', '1'], ['2', '3']].map(&:map.with(&:to_i))
# => [[0, 1], [2, 3]]
[%w(a b), %w(c d)].map(&:inject.with(&:+))
# => ["ab", "cd"] 
[(1..5), (6..10)].map(&:map.with(&:*.with(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]] 

@Arup Rakshit과 나눈 대화는 다음과 같습니다. 자세한 설명은 다음과 같습니다.
Ruby에서 map(&:method) 구문에 인수를 제공할 수 있습니까?


아래 의견에서 @amcaplan이 제안한 것처럼, 만약 당신이 이름을 바꾼다면, 당신은 더 짧은 구문을 만들 수 있습니다.with하는 방법.call이 경우 루비에는 이 특수 메서드에 대한 바로 가기가 내장되어 있습니다..().

따라서 위의 내용을 다음과 같이 사용할 수 있습니다.

class Symbol
  def call(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11] 

[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]] 

여기 정교함을 사용하는 버전이 있습니다(글로벌 원숭이 패치보다 덜 촌스럽습니다).Symbol):

module AmpWithArguments

  refine Symbol do
    def call(*args, &block)
      ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
    end
  end

end

using AmpWithArguments

a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11] 

[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]] 

당신의 예는 할 수 있습니다.a.map(&2.method(:+)).

Arup-iMac:$ pry
[1] pry(main)> a = [1,3,5,7,9]
=> [1, 3, 5, 7, 9]
[2] pry(main)> a.map(&2.method(:+))
=> [3, 5, 7, 9, 11]
[3] pry(main)> 

작동 방식은 다음과 같습니다.

[3] pry(main)> 2.method(:+)
=> #<Method: Fixnum#+>
[4] pry(main)> 2.method(:+).to_proc
=> #<Proc:0x000001030cb990 (lambda)>
[5] pry(main)> 2.method(:+).to_proc.call(1)
=> 3

2.method(:+)개체를 제공합니다.그리고나서&2.method(:+)실제로 통화 방법, 그것을 만드는 것.Proc물건.그런 다음 Ruby에서 &: 연산자를 뭐라고 부릅니까?

당신이 링크한 게시물이 확인하듯이,a.map(&:class)의 줄임말이 아닙니다.a.map {|x| x.class}을 제외하고는a.map(&:class.to_proc).

즉,to_proc다음에 오는 것은 무엇이든 호출됩니다.&교환입니다.

그래서 당신은 그것을 직접 줄 수 있습니다.Proc대신:

a.map(&(Proc.new {|x| x+2}))

나는 이것이 아마도 당신의 질문의 목적을 좌절시킬 것이라는 것을 알지만, 나는 그것을 우회할 다른 방법을 볼 수 없습니다. 당신이 어떤 방법을 부를 것인지를 지정하는 것이 아니라, 당신은 그것에 응답하는 것을 전달할 뿐입니다.to_proc.

제 생각에는 두 가지 주장에만 적합한 열거형에 대한 다른 네이티브 옵션이 있습니다.학급.Enumerable는 메서드 " 이법있습다니방다니▁method있▁the"를 사용합니다.with_object그리고 나서 다른 것을 반환합니다.Enumerable.

그래서 당신은 전화할 수 있습니다.&각 항목과 개체를 인수로 사용하는 메서드에 대한 연산자입니다.

예:

a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+) # => [3, 5, 7, 9, 11]

더 많은 논쟁을 원한다면 성공을 반복해야 하지만 제 생각에는 추악합니다.

a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+).to_enum.with_object(5).map(&:+) # => [8, 10, 12, 14, 16]

단답: 아니요.

@rkon의 답변에 따라 다음과 같은 작업을 수행할 수도 있습니다.

a = [1,3,5,7,9]
a.map &->(_) { _ + 2 } # => [3, 5, 7, 9, 11]

인수로 필요한 모든 메서드가 배열의 요소인 경우 이 방법이 가장 간단한 방법일 수 있습니다.

def double(x)
  x * 2
end

[1, 2, 3].map(&method(:double))

=> [2, 4, 6]

수용된 답변처럼 핵심 클래스를 직접 패치하는 대신 패싯 보석의 기능을 사용하는 것이 더 짧고 깨끗합니다.

require 'facets'
a = [1,3,5,7,9]
a.map &:+.(2)

아무도 사용에 대해 언급하지 않은 것이 놀랍습니다.curry하지만, 이것은 루비 2.2.9 이후로 루비에 있었습니다.표준 Ruby 라이브러리를 사용하여 OP가 원하는 방식으로 수행할 수 있는 방법은 다음과 같습니다.

[1,3,5,7,9].map(&:+.to_proc.curry(2).call(11))
# => [12, 14, 16, 18, 20]

다에대배제합야니다해공열을음한에 .curry통화 내용과 일치합니다. 통역사는 때문입니다.+방법은 아직 참조합니다.이는 또한 의 모든 개체가 다음에 있을 때만 사용할 수 있음을 의미합니다.map같은 성질을 가지런티를 가지다하지만 이런 식으로 사용하려고 한다면 문제가 되지 않을 것입니다.

잘모어요겠에 잘 모르겠습니다.Symbol#with이미 게시되었으며, 상당히 단순화되었으며 잘 작동합니다.

class Symbol
  def with(*args, &block)
    lambda { |object| object.public_send(self, *args, &block) }
  end
end

(으)로 사용)public_sendsend비공개 메소드 호출을 방지하기 위해서도caller루비가 이미 사용하고 있어서 혼란스러웠습니다.)

언급URL : https://stackoverflow.com/questions/23695653/can-you-supply-arguments-to-the-mapmethod-syntax-in-ruby

반응형