रूबी में मानचित्र (और: नाम) का क्या अर्थ है?


495

मुझे यह कोड RailsCast में मिला :

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end

क्या करता है (&:name)में map(&:name)मतलब?


122
मैंने इसे "प्रेट्ज़ेल कोलोन" कहा है, वैसे।
जोश ली

6
Haha। मुझे पता है कि एक Ampersand के रूप में। मैंने इसे कभी भी "प्रेट्ज़ेल" नहीं सुना, लेकिन यह समझ में आता है।
ड्रैगनफैक्स

74
इसे "प्रेट्ज़ेल कोलन" कहना भ्रामक है, हालांकि आकर्षक है। माणिक में कोई "और:" नहीं है। एम्परसेंड (&) एक "यूनी एम्पर्सैंड ऑपरेटर" है जिसे एक साथ धकेला गया है: प्रतीक। यदि कुछ भी है, तो यह एक "प्रेट्ज़ेल प्रतीक" है। बस केह रहा हू।
फॉन्टो

3
tags.map (&: name) टैग्स से सॉर्ट किया गया है ।मैप {| s | s.name}
शर्मा

3
"प्रेट्ज़ेल कोलन" एक दर्दनाक चिकित्सीय स्थिति की तरह लगता है ... लेकिन मुझे इस प्रतीक का नाम पसंद है :)
zmorris

जवाबों:


517

इसके लिए आशुलिपि है tags.map(&:name.to_proc).join(' ')

यदि fooएक to_procविधि के साथ एक वस्तु है , तो आप इसे एक विधि के रूप में पास कर सकते हैं &foo, जो foo.to_procउस विधि के ब्लॉक के रूप में कॉल और उपयोग करेगा ।

Symbol#to_procविधि मूल रूप से ActiveSupport से जोड़ा गया है लेकिन रूबी 1.8.7 में एकीकृत किया गया। यह इसका कार्यान्वयन है:

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

41
यह मेरा एक बेहतर जवाब है।
ओलिवर एन।

91
टैग.मैप (: name.to_proc) खुद टैग के लिए एक आशुलिपि है। टैग {| टैग | tag.name}
सिमोन

5
यह वैध रूबी कोड नहीं है, फिर भी आपको इसकी आवश्यकता है &, अर्थातtags.map(&:name.to_proc).join(' ')
घोड़ा

5
प्रतीक # to_proc को C में लागू किया जाता है, रूबी में नहीं, लेकिन यही वह है जो रूबी में दिखेगा।
एंड्रयू ग्रिम

5
@AndrewGrimm यह पहली बार रूबी में पटरियों पर जोड़ा गया था, उस कोड का उपयोग करके। इसे तब 1.8.7 संस्करण में एक देशी रूबी फीचर के रूप में जोड़ा गया था।
कैमरन मार्टिन

174

एक और शांत आशुलिपि, कई के लिए अज्ञात है

array.each(&method(:foo))

जो एक आशुलिपि है

array.each { |element| foo(element) }

कॉल करके method(:foo)हमने उससे एक Methodवस्तु ली selfजो उसकी fooविधि का प्रतिनिधित्व करता है, और &यह दर्शाता है कि यह एक to_proc विधि है जो इसे एक में परिवर्तित करती है Proc

यह बहुत उपयोगी है जब आप चीजों को बिंदु-मुक्त शैली करना चाहते हैं। एक उदाहरण यह देखना है कि क्या स्ट्रिंग में कोई स्ट्रिंग है जो स्ट्रिंग के बराबर है "foo"। पारंपरिक तरीका है:

["bar", "baz", "foo"].any? { |str| str == "foo" }

और बिंदु मुक्त तरीका है:

["bar", "baz", "foo"].any?(&"foo".method(:==))

पसंदीदा तरीका सबसे अधिक पठनीय होना चाहिए।


25
array.each{|e| foo(e)}अभी भी छोटा है :-) +1 कहीं भी
जेरेड बेक

क्या आप किसी अन्य वर्ग के निर्माण का उपयोग कर सकते हैं &method?
होलोग्राफिक-सिद्धांत

3
@finishingmove हाँ मुझे लगता है। इसे आज़माएं[1,2,3].map(&Array.method(:new))
Gerry


45

जबकि हम यह भी ध्यान दें कि एम्परसेंड #to_procजादू किसी भी वर्ग के साथ काम कर सकता है, केवल प्रतीक नहीं। कई रुबाइयाँ #to_procऐरे वर्ग पर परिभाषित करने के लिए चुनते हैं :

class Array
  def to_proc
    proc { |receiver| receiver.send *self }
  end
end

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]

Ampersand अपने ऑपरेंड पर संदेश &भेजकर काम करता है to_proc, जो उपरोक्त कोड में, ऐरे वर्ग का है। और जब से मैंने #to_procऐरे पर विधि को परिभाषित किया , रेखा बन गई:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }

यह शुद्ध सोना है!
कुंभ

38

इसके लिए आशुलिपि है tags.map { |tag| tag.name }.join(' ')


नहीं, यह रूबी 1.8.7 और इसके बाद के संस्करण में है।
चक

क्या यह मानचित्र के लिए एक सरल मुहावरा है या रूबी हमेशा एक विशेष तरीके से 'और' की व्याख्या करती है?
कोलिमार्को

7
@ कोल्लीमारको: जैसा कि जेलेडव अपने जवाब में कहते हैं, एकरी &ऑपरेटर to_procअपने ऑपरेंड पर कॉल करता है। तो यह मानचित्र विधि के लिए विशिष्ट नहीं है, और वास्तव में किसी भी विधि पर काम करता है जो ब्लॉक लेता है और ब्लॉक को एक या अधिक तर्क देता है।
चक

36
tags.map(&:name)

के समान है

tags.map{|tag| tag.name}

&:name सिर्फ़ प्रतीक का उपयोग विधि नाम के रूप में किया जाता है।


1
जवाब मैं विशेष रूप से procs के लिए (बल्कि यह अनुरोधकर्ताओं का सवाल था) के लिए देख रहा था
matrim_c

अच्छा उत्तर! मेरे लिए अच्छी तरह से स्पष्ट किया।
आपदाना

14

जोश ली का उत्तर लगभग सही है सिवाय इसके कि रूबी कोड निम्नानुसार होना चाहिए था।

class Symbol
  def to_proc
    Proc.new do |receiver|
      receiver.send self
    end
  end
end

नहीं

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

इस कोड के साथ, जब print [[1,'a'],[2,'b'],[3,'c']].map(&:first)निष्पादित किया जाता है, रूबी [1,'a']1 में पहला इनपुट और 'a' को obj1 और args*'a' को एक त्रुटि का कारण बनाता है क्योंकि Fixnum ऑब्जेक्ट 1 में स्वयं विधि नहीं है (जो है: पहला)।


जब [[1,'a'],[2,'b'],[3,'c']].map(&:first)निष्पादित किया जाता है;

  1. :firstएक प्रतीक वस्तु है, इसलिए जब &:firstएक पैरामीटर के रूप में मानचित्र विधि को दिया जाता है , तो Symbol # to_proc लागू किया जाता है।

  2. मानचित्र कॉल मैसेज भेजता है: पैरामीटर के साथ first.to_proc [1,'a'], उदाहरण के लिए, :first.to_proc.call([1,'a'])निष्पादित किया जाता है।

  3. प्रतीक में to_proc प्रक्रिया कक्षा के लिए एक सरणी वस्तु ( [1,'a']) के साथ एक संदेश भेजता है पैरामीटर (: पहला), उदाहरण के लिए, [1,'a'].send(:first)निष्पादित किया जाता है।

  4. [[1,'a'],[2,'b'],[3,'c']]ऑब्जेक्ट में बाकी तत्वों से अधिक पुनरावृत्त होता है ।

यह [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)अभिव्यक्ति को निष्पादित करने के समान है ।


1
जोश ली का जवाब बिलकुल सही है, जैसा कि आप सोचकर देख सकते हैं [1,2,3,4,5,6].inject(&:+)- इंजेक्शन एक लैम्ब्डा की उम्मीद दो मापदंडों (मेमो और आइटम) से करता है और :+.to_procइसे डिलीवर करता है - Proc.new |obj, *args| { obj.send(self, *args) }या{ |m, o| m.+(o) }
उरई अगासी

11

यहां दो चीजें हो रही हैं, और दोनों को समझना जरूरी है।

जैसा कि अन्य उत्तरों में वर्णित है, Symbol#to_procविधि कहा जा रहा है।

लेकिन इसका कारण to_procप्रतीक पर कहा जा रहा है क्योंकि इसे mapएक ब्लॉक तर्क के रूप में पारित किया जा रहा है। &एक विधि कॉल में एक तर्क के सामने रखने से यह इस तरह से पारित हो जाता है। यह किसी भी रूबी विधि के लिए सही है, न कि केवल mapप्रतीकों के साथ।

def some_method(*args, &block)
  puts "args: #{args.inspect}"
  puts "block: #{block.inspect}"
end

some_method(:whatever)
# args: [:whatever]
# block: nil

some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>

some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)

Symbolएक में परिवर्तित हो जाता Procहै क्योंकि यह एक ब्लॉक के रूप में में पारित कर दिया है। हम एम्परसैंड के .mapबिना एक प्रॉप पास करने की कोशिश करके इसे दिखा सकते हैं :

arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true

arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)

arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]

भले ही इसे परिवर्तित करने की आवश्यकता न हो, लेकिन विधि को इसका उपयोग करने का तरीका नहीं पता होगा क्योंकि यह एक ब्लॉक तर्क की अपेक्षा करता है। साथ इसे पारित &देता .mapब्लॉक यह उम्मीद है।


यह ईमानदारी से दिया गया सर्वश्रेष्ठ उत्तर है। आप एम्परसेंड के पीछे के तंत्र की व्याख्या करते हैं और हम एक खरीद के साथ क्यों समाप्त होते हैं, जो मुझे आपके उत्तर तक नहीं मिला। धन्यवाद।
फ्राकॉन

5

(&: नाम) के लिए संक्षिप्त है (&: name.to_proc) यह उसी तरह है tags.map{ |t| t.name }.join(' ')

to_proc वास्तव में C में लागू किया गया है


5

नक्शा (और: नाम) एक अनुपलब्ध वस्तु लेता है (आपके मामले में टैग) और प्रत्येक तत्व / टैग के लिए नाम विधि चलाता है, विधि से प्रत्येक लौटा मूल्य का उत्पादन करता है।

यह एक आशुलिपि है

array.map { |element| element.name }

जो तत्व (टैग) नामों की सरणी देता है


2

हालांकि हमारे पास पहले से ही शानदार जवाब हैं, एक शुरुआत के परिप्रेक्ष्य में देखकर मैं अतिरिक्त जानकारी जोड़ना चाहूंगा:

रूबी में मानचित्र (और: नाम) का क्या अर्थ है?

इसका मतलब है, कि आप मानचित्र फ़ंक्शन के पैरामीटर के रूप में एक और विधि पारित कर रहे हैं। (वास्तव में आप एक प्रतीक को पारित कर रहे हैं जो एक खरीद में परिवर्तित हो जाता है। लेकिन इस विशेष मामले में यह उतना महत्वपूर्ण नहीं है)।

जो महत्वपूर्ण है वह यह है कि आपके पास एक ऐसा methodनाम nameहै जो मानचित्र विधि द्वारा पारंपरिक blockशैली के बजाय एक तर्क के रूप में उपयोग किया जाएगा ।


2

यह मूल रूप tag.nameसे सरणी में प्रत्येक टैग पर विधि कॉल को निष्पादित करता है ।

यह एक सरलीकृत रूबी शॉर्टहैंड है।


1

यहाँ :nameप्रतीक है जो nameटैग ऑब्जेक्ट की विधि को इंगित करता है । जब हम पास &:nameहोते हैं map, तो यह nameएक खरीद वस्तु के रूप में माना जाएगा । संक्षेप में, tags.map(&:name)निम्नानुसार कार्य करता है:

tags.map do |tag|
  tag.name
end


1

सबसे पहले, के &:nameलिए एक शॉर्टकट है &:name.to_proc, जहां :name.to_procएक रिटर्न Proc(कुछ ऐसा ही है, लेकिन एक लैम्ब्डा के समान नहीं है) कि जब एक वस्तु के साथ कहा जाता है (पहली) तर्क, nameउस ऑब्जेक्ट पर विधि को कॉल करता है ।

दूसरे, धर्मान्तरित &में जबकि def foo(&block) ... endएक ब्लॉक पारित करने के fooलिए Proc, यह जब एक करने के लिए लागू विपरीत करता है Proc

इस प्रकार, &:name.to_procएक ब्लॉक है जो ऑब्जेक्ट को तर्क के रूप में लेता है और उस nameपर विधि कहता है, अर्थात { |o| o.name }


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.