ও (এন) এর চেয়ে দ্রুত অ্যারের উপাদানগুলির সূচক পান


104

প্রদত্ত আমার কাছে একটি বিশাল অ্যারে এবং এর থেকে একটি মান রয়েছে। আমি অ্যারেতে মান সূচক পেতে চাই। অন্য কোনও উপায় আছে, বরং তা পাওয়ার জন্য কল করুন Array#index? সমস্যাটি আসলেই বিশাল আকারের অ্যারে রাখা এবং Array#indexপ্রচুর পরিমাণে কল করা প্রয়োজন থেকে আসে ।

বেশ কয়েকবার চেষ্টা করার পরে আমি দেখতে পেলাম যে মানগুলির(value, index) পরিবর্তে ক্ষেত্রগুলি দিয়ে স্ট্রাক্ট সংরক্ষণ করে উপাদানগুলির অভ্যন্তরে ক্যাচিং সূচকগুলি কার্য সম্পাদনকে একটি বিশাল পদক্ষেপ দেয় (20x বার জয়)।

তবুও আমি অবাক হয়েছি কী ক্যাচিং ছাড়াই এন এলিমেন্টের সূচকগুলি খুঁজে পাওয়ার আরও সুবিধাজনক উপায় আছে (অথবা এমন একটি ভাল ক্যাশিং কৌশল রয়েছে যা কার্য সম্পাদনকে উত্সাহিত করবে)।

উত্তর:


118

অ্যারেটিকে একটি হ্যাশে রূপান্তর করুন। তারপরে চাবিটি সন্ধান করুন।

array = ['a', 'b', 'c']
hash = Hash[array.map.with_index.to_a]    # => {"a"=>0, "b"=>1, "c"=>2}
hash['b'] # => 1

2
দ্রুততম যদি অ্যারেটি দীর্ঘ হয়
কেভিন

17
আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে যদি সদৃশ মান থাকে তবে এটি সমস্যাযুক্ত হতে পারে। উপরে বর্ণিত পদ্ধতিটি সমপরিমাণ বা # রাইন্ডেক্স (মানটির শেষ ঘটনা) ফিরে আসবে # ইন্ডেক্স সমমানের ফলাফল পাওয়ার জন্য, হ্যাশটির অর্থের প্রথম সূচকটি ফেরত দেওয়ার অর্থ যা আপনাকে তৈরির আগে অ্যারেটিকে বিপরীত করার লাইন ধরে কিছু করতে হবে হ্যাশ তারপরে প্রাথমিক অ্যারের মোট দৈর্ঘ্য থেকে ফেরত সূচক মানটি বিয়োগ করে - 1 # (অ্যারে. দৈর্ঘ্য - 1) - হ্যাশ ['বি']
আশোদা

2
হ্যাশে রূপান্তরকরণে ও (এন) সময় লাগে না? আমি মনে করি এটি যদি একাধিকবার ব্যবহার করা হয় তবে হ্যাশ রূপান্তরটি আরও পারফরম্যান্ট হবে। তবে একক ব্যবহারের জন্য, অ্যারের মাধ্যমে পুনরুক্তি করা কি আর আলাদা নয়?
আহ্নবিজক্যাড

হ্যাঁ, এবং সম্ভবত একক ব্যবহারের জন্য খারাপ এটি হ্যাশ গণনা হিসাবে তুলনায় যত তাড়াতাড়ি শর্ট সার্কিট না হিসাবে গুরুত্বপূর্ণ।
পিটার ডিউইউজ

199

কেন সূচক বা রিনডেক্স ব্যবহার করবেন না?

array = %w( a b c d e)
# get FIRST index of element searched
puts array.index('a')
# get LAST index of element searched
puts array.rindex('a')

সূচী: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-index

রিনডেক্স: http://www.ruby-doc.org/core-1.9.3/Array.html# মেমোডিক- i-rindex


13
বড় বড় আকারের অ্যারের কারণে ওপি ঠিক এটাই বলেছিল যে তারা চায় না। অ্যারে # সূচকটি হ'ল (এন) এবং একাধিকবার এটি করা পারফরম্যান্সের উপর আঘাত হানবে। হ্যাশ লুক হ'ল ও (1)।
টিম

4
@ টিম, আমি আমার উত্তর দেওয়ার সময় মনে করতে পারি না যে এই একই প্রশ্নটি ছিল, সম্ভবত ওপি পরে প্রশ্নটি সংশোধন করেছে, যা এই উত্তরটিকে অবৈধ করে দেবে।
রজার

3
এটি কি বলে না যে এটি নির্দিষ্ট সময়ে সম্পাদিত হয়েছিল?
টিম

হেই, হ্যাঁ সত্য। ভাল আমি এবং আরও 30 জন তখন এটি পড়ছিলাম। আমার ধারণা: /
রজার

9

অন্যান্য উত্তরগুলি অ্যারেতে একাধিকবার তালিকাভুক্ত এন্ট্রি হওয়ার সম্ভাবনা বিবেচনা করে না। এটি একটি হ্যাশ ফিরিয়ে দেবে যেখানে প্রতিটি কী অ্যারেতে একটি অনন্য বস্তু এবং প্রতিটি মান সূচকগুলির একটি অ্যারে যা বস্তুটি যেখানে বাস করে তার সাথে সম্পর্কিত:

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

indices = a.each_with_index.inject(Hash.new { Array.new }) do |hash, (obj, i)| 
    hash[obj] += [i]
    hash
end
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5], 4 => [6] }

এটি সদৃশ এন্ট্রিগুলির জন্য দ্রুত অনুসন্ধানের অনুমতি দেয়:

indices.select { |k, v| v.size > 1 }
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5] }

6

হ্যাশ ব্যবহার না করার জন্য কি কোনও ভাল কারণ আছে? অ্যারের জন্য লুকআপগুলি O(1)বনাম areO(n)


মুল বক্তব্যটি হ'ল - আমি হ্যাশকে কল করছি #keys, যা আমি ব্যবহার করছি এমন একটি অ্যারে প্রদান করে। তবুও, আমি আমার আর্কিটেকচারটি সম্পর্কেও ভাবতে পারি ...
gmile

3

যদি এটি সাজানো অ্যারে হয় তবে আপনি বাইনারি অনুসন্ধান অ্যালগরিদম ( O(log n)) ব্যবহার করতে পারেন । উদাহরণস্বরূপ, এই কার্যকারিতা সহ অ্যারে-শ্রেণি প্রসারিত করা:

class Array
  def b_search(e, l = 0, u = length - 1)
    return if lower_index > upper_index

    midpoint_index = (lower_index + upper_index) / 2
    return midpoint_index if self[midpoint_index] == value

    if value < self[midpoint_index]
      b_search(value, lower_index, upper_index - 1)
    else
      b_search(value, lower_index + 1, upper_index)
    end
  end
end

3
এটি পড়ার পক্ষে আসলে এতটা কঠিন নয়। প্রথম অংশ, নিম্ন সীমাটি উপরের বাউন্ডের চেয়ে বড় হলে ফিরে আসুন (পুনরাবৃত্তিটি ফাইল করেছে)। দ্বিতীয় অংশটি পরীক্ষা করে আমাদের বাম পাশ বা ডান পাশের প্রয়োজন হয় কিনা তা মাঝখানে পয়েন্ট ই এর সাথে মানটির সাথে তুলনা করে। আমাদের যে উত্তরটি আমরা চাই তা না পেলে আমরা পুনরাবৃত্তি করি।
ioquatix

আমি মনে করি এটি সম্পাদনার চেয়ে জনগণের অহংকারকে আরও উন্নত করে।
আন্দ্রে ফিগুয়েরেদো

2

@ সাওয়ার উত্তর এবং সেখানে তালিকাভুক্ত মন্তব্যের সংমিশ্রণ নিয়ে আপনি অ্যারে শ্রেণিতে একটি "দ্রুত" সূচক এবং রিনডেক্স প্রয়োগ করতে পারেন।

class Array
  def quick_index el
    hash = Hash[self.map.with_index.to_a]
    hash[el]
  end

  def quick_rindex el
    hash = Hash[self.reverse.map.with_index.to_a]
    array.length - 1 - hash[el]
  end
end

2

যদি আপনার অ্যারেতে একটি প্রাকৃতিক অর্ডার থাকে তবে বাইনারি অনুসন্ধান ব্যবহার করুন।

বাইনারি অনুসন্ধান ব্যবহার করুন।

বাইনারি অনুসন্ধানে O(log n)অ্যাক্সেসের সময় রয়েছে।

বাইনারি অনুসন্ধান কীভাবে ব্যবহার করবেন সে সম্পর্কে এখানে পদক্ষেপ দেওয়া হয়েছে,

  • আপনার অ্যারের অর্ডারটি কী? উদাহরণস্বরূপ, এটি নাম অনুসারে বাছাই করা হয়?
  • bsearchউপাদান বা সূচকগুলি খুঁজে পেতে ব্যবহার করুন

কোড উদাহরণ

# assume array is sorted by name!

array.bsearch { |each| "Jamie" <=> each.name } # returns element
(0..array.size).bsearch { |n| "Jamie" <=> array[n].name } # returns index

0

তবুও আমি অবাক হয়েছি কী ক্যাচিং ছাড়াই এন এলিমেন্টের সূচকগুলি খুঁজে পাওয়ার আরও সুবিধাজনক উপায় আছে (অথবা এমন একটি ভাল ক্যাশিং কৌশল রয়েছে যা কার্য সম্পাদনকে উত্সাহিত করবে)।

আপনি বাইনারি অনুসন্ধান ব্যবহার করতে পারেন (যদি আপনার অ্যারেটি অর্ডার করা হয় এবং অ্যারেতে যে মানগুলি সংরক্ষণ করা হয় তবে কোনও উপায়ে তুলনীয়)। এটি কাজ করার জন্য আপনাকে বাইনারি অনুসন্ধানটি বর্তমান উপাদানটির "বাম দিকে" বা "ডানদিকে" দেখানো উচিত কিনা তা জানাতে সক্ষম হতে হবে। তবে আমি বিশ্বাস করি যে indexসন্নিবেশের সময় সঞ্চিত করা এবং তারপরে যদি আপনি একই অ্যারে থেকে উপাদানটি পান তবে এটি ব্যবহারে কোনও ভুল নেই ।

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