كيف أكتب طريقة للتعامل مع روبي الصفر، واحد، أو العديد من المدخلات؟

StackOverflow https://stackoverflow.com/questions/840136

  •  20-08-2019
  •  | 
  •  

سؤال

ولقد حصلت على طريقة روبي كما يلي:

# Retrieve all fruits from basket that are of the specified kind.
def fruits_of_kind(kind)
  basket.select { |f| f.fruit_type == kind.to_s }
end

والآن، يمكنك استدعاء هذه مثل:

fruits_of_kind(:apple)    # => all apples in basket
fruits_of_kind('banana')  # => all bananas in basket

ووهلم جرا.

وكيف أغير طريقة بحيث أنه سيتم التعامل مع المدخلات iterable وكذلك لا المدخلات والمدخلات معدومة بشكل صحيح؟ على سبيل المثال، أود أن تكون قادرة على دعم:

fruits_of_kind(nil) # => nil
fruits_of_kind(:apple, :banana)    # => all apples and bananas in basket
fruits_of_kind([:apple, 'banana']) # => likewise

هل هذا ممكن القيام به اصطلاحا؟ إذا كان الأمر كذلك، ما هي أفضل طريقة لكتابة أساليب بحيث يمكن أن يقبل الصفر، واحد، أو العديد من المدخلات؟

هل كانت مفيدة؟

المحلول

def fruits_of_kind(kind)
    return nil if kind.nil?

    result = []

    ([] << kind).flatten.each{|k| result << basket.select{|f| f.fruit_type == k.to_s }}

    result
end

والمشغل 'تنبيه' هو على الارجح أفضل وسيلة للذهاب، ولكن هناك أمرين لمشاهدة ل: يمر في شيء أو القوائم. لتعديل حل بيستو لالإدخال / الإخراج الذي تريد، عليك أن تفعل شيئا من هذا القبيل:

def fruits_of_kind(*kinds)
  return nil if kinds.compact.empty? 

  basket.select do |fruit|
    kinds.flatten.each do |kind|
      break true if fruit.fruit_type == kind.to_s
    end == true #if no match is found, each returns the whole array, so == true returns false
  end
end

إذا كنت تمر في شيء، و* تحولها إلى [لا شيء]. إذا كنت ترغب في العودة لا شيء بدلا من قائمة فارغة، لديك لضغط عليه (إزالة الأصفار) إلى []، ثم يعود لا شيء إذا كان فارغا.

إذا كنت تمر في القائمة، مثل [: التفاح، 'الموز']، و* تحولها إلى [[: التفاح، 'الموز']]. انها فرق دقيق، بل انها قائمة عنصر واحد يحتوي على قائمة أخرى، لذلك تحتاج إلى تتسطح أنواع قبل القيام "كل" حلقة. تسطيح وتحويله إلى [: التفاح، 'الموز']، مثل تتوقع، وتعطيك النتائج التي تبحث عنها

تعديل : لوحتى أفضل، وذلك بفضل جريج كامبل:

   def fruits_of_kind(basket, kind)
       return nil if kind.nil?

       kind_list = ([] << kind).flatten.map{|kind| kind.to_s}

       basket.select{|fruit| kind_list.include?(fruit) } 
   end

وOR (باستخدام تنبيه)

   def fruits_of_kind(*kinds)
       return nil if kinds.compact.empty?

       kind_list = kinds.flatten.map{|kind| kind.to_s}

       basket.select{|fruit| kind_list.include?(fruit.fruit_type) } 
   end

نصائح أخرى

وتحتاج إلى استخدام المشغل تنبيه روبي، التي يلتف كل الحجج المتبقية في صفيف وينقلها في:

def foo (a, b, *c)
  #do stuff
end

foo(1, 2) # a = 1, b = 2, c = []
foo(1, 2, 3, 4, 5) #a = 1, b = 2, c = [3, 4, 5]

في الحالة الخاصة بك، يجب أن شيئا مثل هذا العمل:

def fruits_of_kind(*kinds)
  kinds.flatten!
  basket.select do |fruit|
    kinds.each do |kind|
      break true if fruit.fruit_type == kind.to_s
    end == true #if no match is found, each returns the whole array, so == true returns false
  end
end

تحرير

ولقد غيرت رمز لشد أنواع بحيث يمكنك إرسال في القائمة. وهذا الرمز التعامل دخول أي أنواع في كل شيء، ولكن إذا كنت تريد أن ينص صراحة المدخلات nil، إضافة kinds = [] if kinds.nil? الخط في البداية.

استخدم ميزة VARARGS روبي.

# Retrieve all fruits from basket that are of the specified kind.
# notice the * prefix used for method parameter
def fruits_of_kind(*kind)
  kind.each do |x|
    puts x
  end
end

fruits_of_kind(:apple, :orange)
fruits_of_kind()
fruits_of_kind(nil)

و-sasuke

وهناك استخدام معبرة بشكل رائع من تنبيه كحجة لإنشاء مجموعة الذي يعالج المثال الأخير:

def foo(may_or_may_not_be_enumerable_arg)
  arrayified = [*may_or_may_not_be_enumerable_arg]
  arrayified.each do |item|
    puts item
  end
end

obj = "one thing"
objs = ["multiple", "things", 1, 2, 3]

foo(obj)
# one thing
# => ["one thing"]

foo(objs)
# multiple
# things
# 1
# 2
# 3
# => ["multiple", "things", 1, 2, 3]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top