Ruby একটি অ্যারে একটি মান বিদ্যমান কিনা তা পরীক্ষা করুন




arrays (15)

আমি একটি মান 'Dog' এবং একটি অ্যারে ['Cat', 'Dog', 'Bird']

আমি কিভাবে এটি মাধ্যমে looping ছাড়া অ্যারে বিদ্যমান কিনা তা পরীক্ষা করবেন? মূল্য বিদ্যমান কিনা পরীক্ষা করার একটি সহজ উপায় আছে, আরো কিছু?


অন্য উপায় আছে, খুব কাছাকাছি!

ধরুন অ্যারেরটি হল: [সম্পাদনা,: আপডেট,: তৈরি করুন,: দেখান] - সম্ভবত পুরো সাত মারাত্মক / বিশ্রামপূর্ণ পাপ :)

এবং কিছু স্ট্রিং থেকে একটি বৈধ পদক্ষেপ টান ধারণা সঙ্গে আরও খেলনা - বলুন

আমার ভাই আমাকে তার প্রোফাইল আপডেট করতে চান

সমাধান

[ :edit, :update, :create, :show ].select{|v| v if "my brother would like me to update his profile".downcase =~ /[,|.| |]#{v.to_s}[,|.| |]/}

আপনি include? খুঁজছেন include? :

>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true

আপনি যদি ব্যবহার করতে চান না অন্তর্ভুক্ত? আপনি প্রথমে একটি অ্যারের মধ্যে উপাদান মোড়ানো এবং তারপর আবৃত উপাদান অ্যারে এবং মোড়ানো উপাদান intersection সমান কিনা তা পরীক্ষা করতে পারেন। এটি সমতা উপর ভিত্তি করে একটি বুলিয়ান মান ফিরে আসবে।

def in_array?(array, item)
    item = [item] unless item.is_a?(Array)
    item == array & item
end

আপনি লুপ করতে না চাইলে, অ্যারে দিয়ে এটি করার কোন উপায় নেই। আপনি পরিবর্তে একটি সেট ব্যবহার করা উচিত।

require 'set'
s = Set.new
100.times{|i| s << "foo#{i}"}
s.include?("foo99")
 => true
[1,2,3,4,5,6,7,8].to_set.include?(4) 
  => true

হ্যাশের মতো অভ্যন্তরীণভাবে কাজ করে, তাই আইটেমগুলিকে খুঁজে বের করতে সংগ্রহের মাধ্যমে রুবিটিকে লুপ করতে হবে না, যেহেতু নামটি বোঝায়, এটি কীগুলির হ্যাশ তৈরি করে এবং একটি মেমরি মানচিত্র তৈরি করে যাতে প্রতিটি হ্যাশ মেমরির নির্দিষ্ট বিন্দুতে নির্দেশ করে। একটি হ্যাশের সাথে পূর্ববর্তী উদাহরণটি:

fake_array = {}
100.times{|i| fake_array["foo#{i}"] = 1}
fake_array.has_key?("foo99")
  => true

নেতিবাচক দিক হল সেট এবং হ্যাশ কীগুলি কেবল অনন্য আইটেমগুলি অন্তর্ভুক্ত করতে পারে এবং যদি আপনি অনেকগুলি আইটেম যুক্ত করেন তবে রুবিটিকে একটি বড় মানচিত্র তৈরির জন্য একটি নতুন মানচিত্র তৈরি করতে কিছু সংখ্যক আইটেমের পরে পুরো জিনিসটি পুনরায় লোহা করতে হবে। এই সম্পর্কে আরও জানার জন্য, আমি আপনাকে মাউন্টেনওয়েস্ট রুবিকোফ ২014-এ দেখি নাথান লং দ্বারা গৃহকর্মী হ্যাশে বিগ ও

এখানে একটি বেঞ্চমার্ক আছে:

require 'benchmark'
require 'set'

array = []
set   = Set.new

10_000.times do |i|
  array << "foo#{i}"
  set   << "foo#{i}"
end

Benchmark.bm do |x|
  x.report("array") { 10_000.times { array.include?("foo9999") } }
  x.report("set  ") { 10_000.times { set.include?("foo9999")   } }
end

এবং ফলাফল:

      user     system      total        real
array  7.020000   0.000000   7.020000 (  7.031525)
set    0.010000   0.000000   0.010000 (  0.004816)

এই কাজ করার একাধিক উপায় আছে। তাদের মধ্যে কয়েকটি নিম্নরূপ:

a = [1,2,3,4,5]

2.in? a  #=> true

8.in? a #=> false

a.member? 1 #=> true

a.member? 8 #=> false

একটি in? v3.1 থেকে ActiveSupport (Rails অংশ) পদ্ধতিতে , যেমন @ সিম্পাপারসন দ্বারা নির্দেশিত। তাই Rails এর মধ্যে, অথবা যদি আপনার require 'active_support' তবে আপনি লিখতে পারেন:

'Unicorn'.in?(['Cat', 'Dog', 'Bird']) # => false

OTOH, অপারেটর নেই বা #in? Ruby পদ্ধতিতে নিজেই পদ্ধতি, যদিও এটি আগে প্রস্তাব করা হয়েছে, বিশেষ করে ইউসুক এন্ডোহ রুবি-কোরের শীর্ষ খাঁটি সদস্য।

অন্যদের দ্বারা নির্দিষ্ট হিসাবে, বিপরীত পদ্ধতি include? Array , Hash , Set , Range সহ সমস্ত Enumerable গুলি বিদ্যমান:

['Cat', 'Dog', 'Bird'].include?('Unicorn') # => false

মনে রাখবেন যে আপনার অ্যারের মধ্যে যদি আপনার অনেকগুলি মান থাকে তবে তারা একে অন্যের (অর্থাৎ O(n) ) পরে একটিকে পরীক্ষা করে দেখবে, যখন একটি হ্যাশের জন্য অনুসন্ধানটি ধ্রুবক সময় হবে (অর্থাৎ O(1) )। সুতরাং আপনি অ্যারে ধ্রুবক, উদাহরণস্বরূপ, এটি পরিবর্তে একটি Set ব্যবহার করা একটি ভাল ধারণা। উদাহরণ:

require 'set'
ALLOWED_METHODS = Set[:to_s, :to_i, :upcase, :downcase
                       # etc
                     ]

def foo(what)
  raise "Not allowed" unless ALLOWED_METHODS.include?(what.to_sym)
  bar.send(what)
end

একটি দ্রুত পরীক্ষা প্রকাশ করে যে কলিং include? 10 টি উপাদান Set সমতুল্য Array কল করার চেয়ে প্রায় 3.5x দ্রুত (যদি উপাদান পাওয়া যায় না) হয়।

একটি চূড়ান্ত সমাপ্তি নোট: include? ব্যবহার করে সতর্ক থাকুন include? একটি Range , subtleties আছে, তাই ডক পড়ুন এবং cover? সঙ্গে তুলনা cover? ...


এটা মূল্য কি জন্য, রুবি ডক্স এই ধরনের প্রশ্নের জন্য একটি আশ্চর্যজনক সম্পদ।

আপনি যে অনুসন্ধানের জন্য অনুসন্ধান করছেন তার দৈর্ঘ্যের নোট আমিও নেব। include? পদ্ধতি O (n) জটিলতার সাথে একটি রৈখিক অনুসন্ধান চালাবে যা অ্যারের আকারের উপর নির্ভর করে বেশ কুৎসিত পেতে পারে।

আপনি যদি বড় (সাজানো) অ্যারের সাথে কাজ করেন তবে আমি বাইনারি অনুসন্ধান অ্যালগরিদমটি লিখতে বিবেচনা করব যা খুব কঠিন না হওয়া উচিত এবং এটি O (লগ n) এর সবচেয়ে খারাপ ক্ষেত্রে রয়েছে।

অথবা আপনি রুবি 2.0 ব্যবহার করছেন, আপনি bsearch সুবিধা নিতে পারেন।


এটি আপনাকে কেবল তখনই জানাবে যে এটি বিদ্যমান কিন্তু এটি কত বার প্রদর্শিত হবে:

 a = ['Cat', 'Dog', 'Bird']
 a.count("Dog")
 #=> 1

কিভাবে এই ভাবে?

['Cat', 'Dog', 'Bird'].index('Dog')

চেষ্টা

['Cat', 'Dog', 'Bird'].include?('Dog')

মজার ব্যাপার,

আপনি একটি case এক্সপ্রেশন মধ্যে অ্যারে সদস্যপদ চেক * ব্যবহার করতে পারেন।

case element
when *array 
  ...
else
  ...
end

ক্লোজ যখন সামান্য * লক্ষ্য করুন, এই অ্যারে সদস্যপদ জন্য চেক।

স্প্ল্যাট অপারেটরের সমস্ত স্বাভাবিক যাদু আচরণ প্রয়োগ করা হয়, উদাহরণস্বরূপ যদি array আসলে একটি অ্যারে না তবে একটি উপাদান এটি যে উপাদানটি মিলবে।


যদি আপনার মনে আরো মান থাকে ... আপনি চেষ্টা করতে পারেন:

উদাহরণ: বিড়াল এবং কুকুর অ্যারের মধ্যে উপস্থিত থাকলে:

(['Cat','Dog','Bird'] & ['Cat','Dog'] ).size == 2   #or replace 2 with ['Cat','Dog].size

পরিবর্তে:

['Cat','Dog','Bird'].member?('Cat') and ['Cat','Dog','Bird'].include?('Dog')

নোট: সদস্য? এবং অন্তর্ভুক্ত? সব একই.

এই এক লাইন কাজ করতে পারেন!


রুবি একটি অ্যারে উপাদান খুঁজে 11 পদ্ধতি আছে।

পছন্দের এক include?

বা পুনরাবৃত্তি অ্যাক্সেস, একটি সেট তৈরি এবং তারপর কলিং include? নাকি member?

এখানে তাদের সব,

array.include?(element) # preferred method
array.member?(element)
array.to_set.include?(element)
array.to_set.member?(element)
array.index(element) > 0
array.find_index(element) > 0
array.index { |each| each == element } > 0
array.find_index { |each| each == element } > 0
array.any? { |each| each == element }
array.find { |each| each == element } != nil
array.detect { |each| each == element } != nil

উপাদান উপস্থিত হলে তাদের সব একটি true ish মান ফিরে।

include? পছন্দের পদ্ধতি। অভ্যন্তরীণ rb_equal_opt/rb_equal ফাংশনগুলির সাথে মেলে এমন উপাদানটি লুপের for একটি সি-ভাষা for করে। আপনি পুনরাবৃত্তি সদস্যপদ চেক করার জন্য একটি সেট তৈরি না হওয়া পর্যন্ত এটি আরও বেশি দক্ষতা অর্জন করতে পারে না।

VALUE
rb_ary_includes(VALUE ary, VALUE item)
{
  long i;
  VALUE e;

  for (i=0; i<RARRAY_LEN(ary); i++) {
    e = RARRAY_AREF(ary, i);
    switch (rb_equal_opt(e, item)) {
      case Qundef:
        if (rb_equal(e, item)) return Qtrue;
        break;
      case Qtrue:
        return Qtrue;
    }
  }
  return Qfalse;
}

member? Array ক্লাসে পুনরায় সংজ্ঞায়িত করা হয় না এবং আক্ষরিকভাবে সমস্ত উপাদানের মাধ্যমে সংখ্যার যে Enumerable মডিউল থেকে একটি Enumerable বাস্তবায়ন ব্যবহার করে।

static VALUE
member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
{
  struct MEMO *memo = MEMO_CAST(args);

  if (rb_equal(rb_enum_values_pack(argc, argv), memo->v1)) {
    MEMO_V2_SET(memo, Qtrue);
    rb_iter_break();
  }
  return Qnil;
}

static VALUE
enum_member(VALUE obj, VALUE val)
{
  struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);

  rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
  return memo->v2;
}

রুবি কোড অনুবাদ এই নিম্নলিখিত সম্পর্কে না

def member?(value)
  memo = [value, false, 0]
  each_with_object(memo) do |each, memo|
    if each == memo[0]
      memo[1] = true 
      break
    end
  memo[1]
end

উভয় include? এবং member? O(n) সময় জটিলতার কারণে উভয় প্রত্যাশিত মানের প্রথম ঘটনার জন্য অ্যারে অনুসন্ধান করে।

আমরা অ্যারের একটি হ্যাশ উপস্থাপনা তৈরি করার জন্য O(1) অ্যাক্সেস সময় পেতে একটি সেট ব্যবহার করতে পারি। আপনি বার বার একই অ্যারের সদস্যতা চেক করলে এই প্রাথমিক বিনিয়োগটি দ্রুত পরিশোধ করতে পারে। Set C তে প্রয়োগ করা হয় না তবে সাধারণ রুবি ক্লাস হিসাবে, এখনও অন্তর্নিহিত @hash O(1) অ্যাক্সেসের সময়টি এই @hash তোলে।

এখানে Set ক্লাস বাস্তবায়ন হয়,

module Enumerable
  def to_set(klass = Set, *args, &block)
    klass.new(self, *args, &block)
  end
end

class Set
  def initialize(enum = nil, &block) # :yields: o
    @hash ||= Hash.new
    enum.nil? and return
    if block
      do_with_enum(enum) { |o| add(block[o]) }
    else
      merge(enum)
    end
  end

  def merge(enum)
    if enum.instance_of?(self.class)
      @hash.update(enum.instance_variable_get(:@hash))
    else
      do_with_enum(enum) { |o| add(o) }
    end
    self
  end

  def add(o)
    @hash[o] = true
    self
  end

  def include?(o)
    @hash.include?(o)
  end
  alias member? include?

  ...
end

আপনি Set ক্লাস দেখতে পারেন কেবল একটি অভ্যন্তরীণ @hash ইনস্ট্যান্স তৈরি করে, সমস্ত বস্তুকে @hash মানচিত্র করে এবং তারপর Hash#include? ব্যবহার করে সদস্যতা পরীক্ষা করে Hash#include? যা Hash ক্লাসে O(1) অ্যাক্সেস সময় দ্বারা প্রয়োগ করা হয়।

আমি অন্যান্য 7 পদ্ধতি নিয়ে আলোচনা করব না কারণ তারা সব কম দক্ষ।

উপরে তালিকাভুক্ত 11 এর বাইরেও O(n) জটিলতার সাথে আরও বেশি পদ্ধতি রয়েছে, তবে প্রথম ম্যাচে ব্রেকিংয়ের পরিবর্তে সমগ্র অ্যারে স্ক্যান করার পরে আমি তাদের তালিকা না দেওয়ার সিদ্ধান্ত নিয়েছি।

এই ব্যবহার করবেন না,

# bad examples
array.grep(element).any? 
array.select { |each| each == element }.size > 0
...

Enumerable#include ব্যবহার করুন:

a = %w/Cat Dog Bird/

a.include? 'Dog'

অথবা, যদি অনেকগুলি পরীক্ষা করা হয়, 1 আপনি লুপ পরিত্রাণ পেতে পারেন (যেটি include? ) এবং O (n) থেকে O (1) এ যেতে পারেন:

h = Hash[[a, a].transpose]
h['Dog']

1. আমি আশা করি এটি স্পষ্ট কিন্তু আপত্তিগুলি বন্ধ করতে হবে: হ্যাঁ, কয়েকটি অনুসন্ধানের জন্য, হ্যাশ [] এবং ট্রান্সফার ops প্রোফাইল আয়ত্ত করে এবং প্রতিটি O (n) নিজেই থাকে।


['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'}
=> "Dog"
!['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'}.nil?
=> true




arrays