सवाल क्या आप रुबी में मानचित्र (&: विधि) वाक्यविन्यास के लिए तर्क प्रदान कर सकते हैं?


आप शायद निम्नलिखित रूबी शॉर्टेंड से परिचित हैं (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}

इस वाक्यविन्यास के बारे में और पढ़ें "रूबी में मानचित्र (&: नाम) का क्या अर्थ है?"।

वाक्यविन्यास के माध्यम से &:class, आप एक विधि कॉल कर रहे हैं class प्रत्येक सरणी तत्व के लिए।

मेरा सवाल है: क्या आप विधि कॉल में तर्क प्रदान कर सकते हैं? और यदि हां, तो कैसे?

उदाहरण के लिए, आप निम्न वाक्यविन्यास को कैसे परिवर्तित करते हैं

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

को &: वाक्य - विन्यास?

मैं सुझाव नहीं दे रहा हूं कि &: वाक्यविन्यास बेहतर है। मैं केवल उपयोग करने के यांत्रिकी में रुचि रखते हैं &: तर्क के साथ वाक्यविन्यास।

मुझे लगता है कि आप जानते हैं कि + इंटीजर वर्ग पर एक विधि है। आप irb में निम्नलिखित का प्रयास कर सकते हैं:

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

76
2018-05-16 13:01


मूल




जवाब:


आप पर एक साधारण पैच बना सकते हैं 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" 

या [shorthand] ब्लॉक गुजरने के रूप में कुछ सुपर ठंडा सेवा मेरे शॉर्टेंड ब्लॉक:

[['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]] 

यहां एक वार्तालाप है जिसे मैंने @ArupRakshit के साथ समझाया था:
क्या आप रुबी में मानचित्र (&: विधि) वाक्यविन्यास के लिए तर्क प्रदान कर सकते हैं?


जैसा कि @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]] 

110
2018-05-17 12:55



बहुत दिलचस्प, उरी! - Cary Swoveland
बहुत अच्छा, यह अब तक इस प्रश्न का सबसे अच्छा जवाब है। - Daniël Knippers
बढ़िया, इच्छा है कि यह रूबी कोर का हिस्सा था! - Jikku Jose
@UriAgassi सिर्फ इसलिए कि बहुत से पुस्तकालय ऐसा करते हैं, यह एक अच्छा अभ्यास नहीं करता है। जबकि Symbol#with कोर लाइब्रेरी में मौजूद नहीं हो सकता है और परिभाषित करना कि उस पद्धति को मौजूदा विधि को फिर से परिभाषित करने से कम विनाशकारी है, यह अभी भी बदल रहा है (यानी ओवरराइटिंग) रूबी लाइब्रेरी के कोर क्लास के कार्यान्वयन। अभ्यास बहुत कम और बहुत सावधानी के साथ किया जाना चाहिए। \ n \ n कृपया मौजूदा वर्ग से विरासत में विचार करने और नव निर्मित वर्ग को संशोधित करने पर विचार करें। यह आमतौर पर कोर रूबी कक्षाओं को बदलने के नकारात्मक साइड इफेक्ट्स के बिना तुलनीय परिणाम प्राप्त करता है। - rudolph9
मुझे यह समाधान पसंद है, लेकिन मुझे लगता है कि आप इसके साथ और भी मजेदार हो सकते हैं। एक परिभाषित करने के बजाय with विधि, परिभाषित करें call। फिर आप चीजें कर सकते हैं a.map(&:+.(2)) जबसे object.() का उपयोग करता है #call तरीका। और जब आप इसमें हों, तो आप मजेदार चीजें लिख सकते हैं :+.(2).(3) #=> 5 - LISPy की तरह लगता है, नहीं? - amcaplan


आपके उदाहरण के लिए किया जा सकता है 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(:+) एक देता है Method वस्तु। फिर &, पर 2.method(:+), वास्तव में एक कॉल #to_proc विधि, जो इसे बना रहा है Proc वस्तु। फिर पालन करें आप रूबी में ऑपरेटर को क्या कहते हैं?


36
2018-05-16 13:17



चालाक उपयोग! क्या यह मानता है कि विधि आमंत्रण दोनों तरीकों से लागू किया जा सकता है (यानी arr [element] .method (param) === param.method (arr [element])) या मैं उलझन में हूं? - Kostas Rousis
@ ड्रोन मुझे आपका प्रश्न भी नहीं मिला। लेकिन अगर आप देखते हैं Pry उपरोक्त आउटपुट, आप इसे प्राप्त कर सकते हैं, यह कैसे काम कर रहा है। - Arup Rakshit
@rkon यह दोनों तरीकों से काम नहीं करता है। यह इस विशेष मामले में काम करता है क्योंकि + कम्यूटिव है - sawa
आप कई तर्क कैसे आपूर्ति कर सकते हैं? इस मामले में: a.map {| x | x.method (1,2,3)} - Zack Xu
यह मेरा मुद्दा @ सवा :) है कि यह + के साथ समझ में आता है लेकिन किसी अन्य विधि के लिए नहीं होगा या मान लें कि क्या आप एक्स द्वारा प्रत्येक नंबर को विभाजित करना चाहते हैं। - Kostas Rousis


जिस पोस्ट से आप पुष्टि करते हैं, 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


9
2018-05-16 13:13



यह भी ध्यान रखें कि आप प्रोसेस को स्थानीय चर में सेट कर सकते हैं और उन्हें मानचित्र पर भेज सकते हैं। my_proc = Proc.new{|i| i + 1}, [1,2,3,4].map(&my_proc) => [2,3,4,5] - rudolph9


संक्षिप्त उत्तर: नहीं

@ Rkon के उत्तर के बाद, आप यह भी कर सकते हैं:

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

7
2018-05-16 13:41



तुम सही हो, लेकिन मुझे नहीं लगता &->(_){_ + 2} से कम है {|x| x + 2}। - sawa
ऐसा नहीं है, यही वह है जो @kkon ने अपने जवाब में कहा है, इसलिए मैंने इसे दोहराया नहीं। - Agis
@Agis हालांकि आपका जवाब छोटा नहीं है, यह बेहतर दिखता है। - Jikku Jose
यह एक अद्भुत समाधान है। - BenMorganIO


कोर कक्षाओं को खुद को पकड़ने के बजाय, स्वीकार्य उत्तर में, यह कार्यक्षमता का उपयोग करने के लिए छोटा और क्लीनर है Facets मणि:

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

4
2017-08-26 14:24