আপনি কি রুবিতে মানচিত্রের (এবং: পদ্ধতি) সিনট্যাক্সে যুক্তি সরবরাহ করতে পারেন?


116

আপনি সম্ভবত নিম্নলিখিত রুবি শর্টহ্যান্ডের সাথে পরিচিত ( 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}

থেকে &:সিনট্যাক্সটা কি?

আমি প্রস্তাব দিচ্ছি না যে &:সিনট্যাক্সটি আরও ভাল। আমি কেবল &:যুক্তি দিয়ে সিনট্যাক্স ব্যবহারের যান্ত্রিকগুলিতে আগ্রহী ।

আমি ধরে নিলাম আপনি জানেন যে +এটি পূর্ণসংখ্যা শ্রেণিতে একটি পদ্ধতি। আপনি নীচে থেকে নিম্নলিখিত চেষ্টা করতে পারেন:

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

উত্তর:


139

আপনি এটির 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]] 

@ অরূপক্ষিতের সাথে এটির আরও ব্যাখ্যা দিয়ে আমার এখানে একটি কথোপকথন হয়েছে: আপনি কি রুবিতে
মানচিত্রের (এবং: পদ্ধতি) সিনট্যাক্সে যুক্তি সরবরাহ করতে পারবেন?


@ এমক্যাপ্লান নীচের মন্তব্যে প্রস্তাবিত হিসাবে , আপনি যদি 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]] 

5
দুর্দান্ত, ইচ্ছে করে এই রুবি কোর এর অংশ হত!
জিক্কু জোসে

6
@ উরিআগ্যাসি কেবল অনেকগুলি গ্রন্থাগার এটি করার কারণে এটি একটি ভাল অনুশীলন হয় না। যদিও Symbol#withমূল গ্রন্থাগারে বিদ্যমান না থাকতে পারে এবং রুবি গ্রন্থাগারের মূল শ্রেণীর প্রয়োগ এখনও পরিবর্তিত (অর্থাৎ ওভাররাইটিং) পরিবর্তিত বিদ্যমান পদ্ধতির নতুন সংজ্ঞা দেওয়ার চেয়ে পদ্ধতিটি নির্ধারণ করা কম ধ্বংসাত্মক। অনুশীলনটি খুব অল্প পরিমাণে এবং খুব সাবধানতার সাথে করা উচিত। । n \ n দয়া করে বিদ্যমান বর্গ থেকে উত্তরাধিকার সূত্রে বিবেচনা করুন এবং সদ্য নির্মিত ক্লাসটি সংশোধন করুন। এটি মূল রুবি ক্লাসগুলি পরিবর্তনের নেতিবাচক পার্শ্ব প্রতিক্রিয়া ছাড়াই তুলনামূলক ফলাফল অর্জন করে।
rudolph9

2
@ rudolph9 - আমি পৃথক হতে অনুরোধ করছি - "ওভাররাইট" এর সংজ্ঞাটি কোনও কিছুর উপরে লিখতে হবে , যার অর্থ একটি লিখিত কোড যা আর পাওয়া যায় না এবং এটি স্পষ্টভাবে নয়। Symbolশ্রেণীর উত্তরাধিকার সম্পর্কে আপনার পরামর্শ সম্পর্কে - এটি তুচ্ছ নয় (যদিও সম্ভব হয়), যেহেতু এটি একটি মূল শ্রেণি (এটির কোনও newপদ্ধতি নেই, উদাহরণস্বরূপ), এবং এর ব্যবহার জটিল হবে (এমনকি যদি সম্ভব হয়), যা পরাজিত করবে বর্ধনের উদ্দেশ্য ... যদি আপনি এমন কোনও বাস্তবায়ন দেখাতে পারেন যা এটি ব্যবহার করে এবং তুলনীয় ফলাফল অর্জন করে - দয়া করে ভাগ করুন!
উরি আগাসি

3
আমি এই সমাধানটি পছন্দ করি তবে আমার মনে হয় আপনি এটির সাথে আরও মজা করতে পারেন। কোনও withপদ্ধতি সংজ্ঞায়িত করার পরিবর্তে সংজ্ঞা দিন call। তারপরে আপনি a.map(&:+.(2))যেহেতু পদ্ধতিটি object.()ব্যবহার করেন #callতেমন কিছু করতে পারেন । এবং আপনি যখন এটির সময়ে, আপনি মজাদার জিনিসগুলি লিখতে পারেন :+.(2).(3) #=> 5- এলআইএসপি অনুভব করেন, না?
amcaplan

2
এটি মূলত দেখতে পছন্দ করবে - এটি একটি সাধারণ প্যাটার্ন যা কিছু চিনি আলা। ম্যাপ (&: foo) ব্যবহার করতে পারে
স্টিফেন

48

আপনার উদাহরণ জন্য করা যেতে পারে 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অবজেক্ট তৈরি করে। তারপরে রুবিতে আপনি &: অপারেটরটিকে কী বলে?


চালাক ব্যবহার! এটি কি ধরে নেয় যে পদ্ধতিটি আহ্বানটি উভয় উপায়ে প্রয়োগ করা যেতে পারে (যেমন: আরআর [উপাদান]। মেমোড (প্যারাম) === প্যারাম.মোথড (আরআর [উপাদান])) বা আমি বিভ্রান্ত?
কোস্তাস রুসিস

@ আরকন আমি আপনার প্রশ্নটি পাইনি। আপনি যদি Pryউপরের ফলাফলগুলি দেখতে পান তবে আপনি এটি কীভাবে কাজ করছেন তা পেতে পারেন।
অরূপ রক্ষিত

5
@ আরকন এটি দুইভাবেই কাজ করে না। এটি এই বিশেষ ক্ষেত্রে কাজ করে কারণ +পরিবর্তনশীল।
সাওয়া

আপনি একাধিক যুক্তি সরবরাহ করতে পারেন? যেমন এই ক্ষেত্রে: a.map {| এক্স | এক্স.মোথোড (1,2,3)}
জ্যাক শো

1
এটি আমার সাশ্রয় @ সাওয়া :) এটি + এর সাথে উপলব্ধি করে তবে অন্য পদ্ধতির জন্য তা বোঝায় না বা আপনি যদি প্রতিটি সংখ্যা এক্স দ্বারা ভাগ করতে চান তবে বলতে পারেন
কোস্টাস রুসিস

11

আপনি যে পোস্টটি তার সমর্থক লিঙ্ক হিসাবে, 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


1
এছাড়াও মনে রাখবেন আপনি স্থানীয় ভেরিয়েবলগুলিতে প্রকগুলি সেট করতে এবং সেগুলি মানচিত্রে পাস করতে পারেন। my_proc = Proc.new{|i| i + 1},[1,2,3,4].map(&my_proc) => [2,3,4,5]
rudolph9

10

সংক্ষিপ্ত উত্তর: না

@ আরকনের উত্তর অনুসরণ করে আপনি এটিও করতে পারেন:

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

9
আপনি ঠিক বলেছেন, তবে আমি এর &->(_){_ + 2}চেয়ে কম ছোট বলে মনে করি না {|x| x + 2}
সাওয়া

1
এটি নয়, @ আরকন তার উত্তরে যা বলেছিলেন তাই আমি এটি পুনরুক্ত করিনি।
এগ্রিস

2
@ আপনার উত্তরটি ছোট না হলেও এটি আরও ভাল দেখাচ্ছে।
জিক্কু জোসে

1
এটি একটি দুর্দান্ত সমাধান।
বেনমোরগানআইও

5

মূল ক্লাসগুলিকে নিজেরাই প্যাচিংয়ের পরিবর্তে, গৃহীত উত্তরের মতো, ফেসটস রত্নটির কার্যকারিতাটি ব্যবহার করার জন্য এটি খাটো এবং ক্লিনার :

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

5

গণনার জন্য আর একটি নেটিভ বিকল্প রয়েছে যা আমার মতে দুটি যুক্তির জন্য বেশ সুন্দর। ক্লাসে Enumerableএমন পদ্ধতি রয়েছে 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]

0

আমি Symbol#withইতিমধ্যে পোস্ট করা সম্পর্কে নিশ্চিত নই , আমি এটি বেশ খানিকটা সরলীকরণ করেছি এবং এটি ভালভাবে কাজ করে:

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

(এছাড়াও ব্যক্তিগত পদ্ধতিগুলি কল করা রোধ করার public_sendপরিবর্তে ব্যবহার sendকরে, callerএটি ইতিমধ্যে রুবি দ্বারা ব্যবহৃত হয় তাই এটি বিভ্রান্তিকর ছিল)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.