রুবির মধ্যে তালিকা উপলব্ধি


93

পাইথন তালিকার সমতুল্য সমান করতে, আমি নিম্নলিখিতগুলি করছি:

some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}

এটি করার আরও ভাল উপায় আছে ... সম্ভবত একটি পদ্ধতি কল দিয়ে?


4
আপনার এবং গ্লেন এমসিডোনাল্ডের উত্তর উভয়ই আমার কাছে দুর্দান্ত বলে মনে হচ্ছে ... আপনি যেটির চেয়ে বেশি সংক্ষিপ্ত হওয়ার চেষ্টা করে কী অর্জন করবেন তা আমি দেখতে পাচ্ছি না।
পিস্তোস

4
এই সমাধানটি তালিকাটিকে দুইবার স্থানান্তরিত করে। ইনজেকশন দেয় না।
পেড্রো রোলো

4
এখানে দুর্দান্ত কিছু উত্তর রয়েছে তবে একাধিক সংগ্রহ জুড়ে তালিকার বোঝার জন্য ধারণাটিও দুর্দান্ত লাগবে see
বো জিনেস

উত্তর:


55

আপনি যদি সত্যিই চান, আপনি এটির মতো একটি অ্যারে # অনুধাবন পদ্ধতি তৈরি করতে পারেন:

class Array
  def comprehend(&block)
    return self if block.nil?
    self.collect(&block).compact
  end
end

some_array = [1, 2, 3, 4, 5, 6]
new_array = some_array.comprehend {|x| x * 3 if x % 2 == 0}
puts new_array

মুদ্রণ:

6
12
18

আপনি সম্ভবত এটিই করতেন।


4
আপনি কমপ্যাক্ট ব্যবহার করতে পারে! কিছুটা অপ্টিমাইজ করতে
আলেক্সি

9
এটি আসলে সঠিক নয়, বিবেচনা করুন: [nil, nil, nil].comprehend {|x| x }যা প্রত্যাবর্তন করে []
টেড কাপ্লান

অ্যাক্সেসি, ডক্স অনুসারে, compact!কোনও আইটেম পরিবর্তন করা না গেলে অ্যারের পরিবর্তে শূন্য ফেরত দেয়, তাই আমি মনে করি না এটি কাজ করে।
বাইনারি ফিলি

90

কীভাবে:

some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact

কমপক্ষে আমার স্বাদ থেকে খানিকটা ক্লিনার, এবং আপনার সংস্করণের চেয়ে প্রায় 15% দ্রুত দ্রুত বেনমার্ক পরীক্ষা অনুযায়ী ...


4
পাশাপাশি some_array.map{|x| x * 3 unless x % 2}.compact, যা তর্কযোগ্যভাবে আরও পঠনযোগ্য / রুবি-এস্কো।
নাইটপুল

4
0 রাবিতে সত্যবাদী হওয়ায় @ নাইটপুলের unless x%2কোনও প্রভাব নেই। দেখুন: gist.github.com/jfarmer/2647362
অভিনব শ্রীবাস্তব

30

আমি তিনটি বিকল্প এবং মানচিত্র-কমপ্যাক্টের তুলনায় একটি দ্রুত বেঞ্চমার্ক তৈরি করেছি যা সত্যিই সেরা বিকল্প বলে মনে হচ্ছে।

পারফরম্যান্স পরীক্ষা (রেলস)

require 'test_helper'
require 'performance_test_help'

class ListComprehensionTest < ActionController::PerformanceTest

  TEST_ARRAY = (1..100).to_a

  def test_map_compact
    1000.times do
      TEST_ARRAY.map{|x| x % 2 == 0 ? x * 3 : nil}.compact
    end
  end

  def test_select_map
    1000.times do
      TEST_ARRAY.select{|x| x % 2 == 0 }.map{|x| x * 3}
    end
  end

  def test_inject
    1000.times do
      TEST_ARRAY.inject([]) {|all, x| all << x*3 if x % 2 == 0; all }
    end
  end

end

ফলাফল

/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/performance/list_comprehension_test.rb" -- --benchmark
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
ListComprehensionTest#test_inject (1230 ms warmup)
           wall_time: 1221 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.ListComprehensionTest#test_map_compact (860 ms warmup)
           wall_time: 855 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.ListComprehensionTest#test_select_map (961 ms warmup)
           wall_time: 955 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.
Finished in 66.683039 seconds.

15 tests, 0 assertions, 0 failures, 0 errors

4
reduceএই বেঞ্চমার্কেও দেখতে আকর্ষণীয় হবে ( স্ট্যাকওভারফ্লো . com/a/17703276 দেখুন )।
অ্যাডাম লিন্ডবার্গ 20'15

মানচিত্র_কম্প্যাক্ট দ্রুততর হতে পারে তবে এটি একটি নতুন অ্যারে তৈরি করছে। উদ্বুদ্ধ map.compact এবং select.map চেয়ে স্থান কার্যকরী
bibstha

11

তালিকা অনুধাবন কী তা নিয়ে এই থ্রেডে রুবি প্রোগ্রামারদের মধ্যে কিছু বিভ্রান্তি রয়েছে বলে মনে হয়। প্রতিটি একক প্রতিক্রিয়া রূপান্তরিত করার জন্য কিছু পূর্বনির্মাণ অ্যারে ধরে নেয়। তবে তালিকাটি বোঝার শক্তি নীচের বাক্য গঠন সহ ফ্লাইতে তৈরি একটি অ্যারেতে রয়েছে:

squares = [x**2 for x in range(10)]

নিম্নলিখিতটি রুবিতে একটি এনালগ হবে (এই থ্রেডের একমাত্র পর্যাপ্ত উত্তর, এএফএসি):

a = Array.new(4).map{rand(2**49..2**50)} 

উপরের ক্ষেত্রে, আমি এলোমেলো পূর্ণসংখ্যার একটি অ্যারে তৈরি করছি, তবে ব্লকটিতে কিছু থাকতে পারে। তবে এটি রুবি তালিকার বোঝাপড়া হবে।


4
ওপি যা করার চেষ্টা করছে আপনি কীভাবে করবেন?
অ্যান্ড্রু গ্রিম

4
আসলে আমি এখন দেখতে পাচ্ছি যে ওপিতে নিজেই লেখকের রূপান্তর করতে চেয়েছিলেন এমন কিছু তালিকা রয়েছে। তবে তালিকা অনুধাবনের প্রত্নতাত্ত্বিক ধারণার মধ্যে এমন একটি অ্যারে / তালিকা তৈরি করা জড়িত যেখানে কিছু পুনরাবৃত্তি উল্লেখ করে এর আগে উপস্থিত ছিল না। তবে আসলে কিছু আনুষ্ঠানিক সংজ্ঞা বলছে যে তালিকা অনুধাবন মানচিত্রটি মোটেও ব্যবহার করতে পারে না, তাই আমার সংস্করণটি কোশারও নয় - তবে রুবিতে যেমন অনুমান করা যায় তত কাছাকাছি।
চিহ্নিত করুন

6
আপনার রুবি উদাহরণটি কীভাবে আপনার পাইথনের উদাহরণের অ্যানালগ হিসাবে বিবেচিত হবে তা আমি পাই না। রুবি কোডটি পড়তে হবে: স্কোয়ারস = (0..9)। ম্যাপ {| এক্স | x ** 2}
মিচাউ

4
@ মিমাচু ঠিক থাকলেও, তালিকা বোঝার সম্পূর্ণ বিন্দু (যা চিহ্নিত করা অবহেলিত) হ'ল তালিকান বোধগম্যতা অ্যারে তৈরি করে না - এটি স্ট্রিমিং পদ্ধতিতে সমস্ত গণনা করার জন্য জেনারেটর এবং কো রুটিনগুলি ব্যবহার করে মোটেও স্টোরেজ বরাদ্দ না করে (ব্যতীত) টেম্প ভেরিয়েবল) (যদি if) ফলাফলগুলি একটি অ্যারে ভেরিয়েবলের অবতরণ করে - ফলাফলের সেটটিতে বোধগম্যতা ভেঙে ফেলার জন্য অজগর উদাহরণের বর্গাকার বন্ধনীগুলির উদ্দেশ্য এটি। রুবির জেনারেটরের মতো কোনও সুবিধা নেই।
30:30

4
ওহ হ্যাঁ, এটি রয়েছে (রুবি ২.০ থেকে): স্কোয়ার_স_আল_সৌনিক_নম্বার = (0..ফ্লিট :: ইনফিনিটি) .lazy.map {| x | x ** 2}; পি স্কোয়ার_সাম_ সমস্ত_ প্রাকৃতিক_সংখ্যা.টেক (10)। তো_এ
মিচাও

11

আমি এই বিষয়টিকে নিয়ে রেন হেনরিচের সাথে আলোচনা করেছি, যিনি আমাকে বলেন যে সবচেয়ে ভাল পারফরম্যান্স সমাধান solution

map { ... }.compact

এটি সুবোধ তৈরি করে কারণ এটি অপরিবর্তনীয় ব্যবহারের মতো মধ্যবর্তী অ্যারে তৈরি করা Enumerable#injectএড়িয়ে যায় এবং এটি অ্যারে বৃদ্ধি করা এড়ায়, যা বরাদ্দ সৃষ্টি করে। এটি অন্য কারোর মতোই সাধারণ, যদি না আপনার সংগ্রহে শূন্য উপাদান থাকতে পারে।

আমি এর সাথে তুলনা করি না

select {...}.map{...}

এটি সম্ভব যে রুবির সি বাস্তবায়নও Enumerable#selectখুব ভাল।


9

একটি বিকল্প সমাধান যা প্রতিটি প্রয়োগে কাজ করে এবং ও (2 এন) সময়ের পরিবর্তে ও (এন) এ চালিত হয় তা হ'ল:

some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}

11
আপনি বলতে চাইছেন এটি কেবল একবারে তালিকাটিকে পিছনে ফেলে। আপনি যদি আনুষ্ঠানিক সংজ্ঞা অনুসারে যান, O (n) সমান O (2n)। শুধু নিটপিকিং :)
ড্যানিয়েল হিপার

4
@ ড্যানিয়েল হার্পার :) কেবলমাত্র আপনি সঠিক নন, তবে গড় ক্ষেত্রেও কিছু তালিকা প্রবেশের জন্য তালিকাকে একবারে বদলানো, এবং তারপরে আবার কোনও অপারেশন করাও গড় ক্ষেত্রে তাত্ক্ষণিকভাবে আরও ভাল হতে পারে :)
পেড্রো রোলো

অন্য কথায়, আপনি করছেন 2জিনিষ nপরিবর্তে বার 1জিনিস nবার এবং তারপর অন্য 1জিনিস nবার :) এক গুরুত্বপূর্ণ সুবিধা inject/ reduceএটি কোন সংরক্ষিত কিতাব nilইনপুট ক্রম যা প্রায়ই তালিকা-comprehensionly আচরণ মান
জন লা রয়

8

আমি সবেমাত্র রুবিগেমসকে বোঝার রত্ন প্রকাশ করেছি , যা আপনাকে এটি করতে দেয়:

require 'comprehend'

some_array.comprehend{ |x| x * 3 if x % 2 == 0 }

এটি সিতে লেখা; অ্যারেটি কেবল একবার ট্র্যাভার করা হয়।


7

গণনার একটি grepপদ্ধতি রয়েছে যার প্রথম তর্কটি প্রিকিকেট প্রোক হতে পারে এবং যার বিকল্প argument চ্ছিক দ্বিতীয় যুক্তি একটি ম্যাপিং ফাংশন; সুতরাং নিম্নলিখিত কাজ করে:

some_array.grep(proc {|x| x % 2 == 0}) {|x| x*3}

এটি অন্যান্য কয়েকটি পরামর্শের মতো পঠনযোগ্য নয় (আমি অ্যানোইয়াকের সহজ select.mapবা হিস্ট্রোক্রেটের বোঝার রত্নটি পছন্দ করি) তবে এর শক্তিগুলি এটি ইতিমধ্যে স্ট্যান্ডার্ড লাইব্রেরির অংশ, এবং একক-পাস এবং অস্থায়ী মধ্যবর্তী অ্যারে তৈরি করার সাথে জড়িত না , এবং nilব্যবহারের compactপরামর্শগুলিতে ব্যবহারের মতো সীমার বাইরে মান প্রয়োজন হয় না ।



4
[1, 2, 3, 4, 5, 6].collect{|x| x * 3 if x % 2 == 0}.compact
=> [6, 12, 18]

সেটা আমার জন্য কাজ করে. এটিও পরিষ্কার। হ্যাঁ, এটি এর মতোই mapতবে আমি মনে করি collectকোডটি আরও বোধগম্য।


select(&:even?).map()

এটি নীচে দেখার পরে আসলে আরও ভাল দেখাচ্ছে।


2

ভালো লেগেছে পেড্রো উল্লেখ করা হয়েছে, আপনাকে শৃঙ্খলিত কল একসঙ্গে দ্রব করতে Enumerable#selectএবং Enumerable#mapনির্বাচিত উপাদানের উপর একটি ট্র্যাভেরসাল এড়ানো। এটি সত্য কারণ Enumerable#selectভাঁজ বা এর একটি বিশেষীকরণ inject। আমি রুবি সাব্রেডডিটে এই বিষয়টির তাত্ক্ষণিক পরিচয় পোস্ট করেছি ।

অ্যারে রূপান্তরগুলি ম্যানুয়ালি ফিউজ করা বিরক্তিকর হতে পারে, তাই সম্ভবত কেউ comprehendএই select/ mapপ্যাটার্নটিকে সুন্দর করার জন্য রবার্ট গাম্বলের প্রয়োগের সাথে খেলতে পারে ।


2

এটার মতো কিছু:

def lazy(collection, &blk)
   collection.map{|x| blk.call(x)}.compact
end

ডাকা:

lazy (1..6){|x| x * 3 if x.even?}

যা ফেরত:

=> [6, 12, 18]

lazyঅ্যারে এবং তারপরে সংজ্ঞায়িত করার সাথে কী সমস্যা হয়েছে :(1..6).lazy{|x|x*3 if x.even?}
গাস

1

আর একটি সমাধান তবে সম্ভবত সেরা নয়

some_array.flat_map {|x| x % 2 == 0 ? [x * 3] : [] }

বা

some_array.each_with_object([]) {|x, list| x % 2 == 0 ? list.push(x * 3) : nil }

0

এটির কাছে যাওয়ার এই এক উপায়:

c = -> x do $*.clear             
  if x['if'] && x[0] != 'f' .  
    y = x[0...x.index('for')]    
    x = x[x.index('for')..-1]
    (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
    x.insert(x.length, "end; $*")
    eval(x)
    $*)
  elsif x['if'] && x[0] == 'f'
    (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << x")
    x.insert(x.length, "end; $*")
    eval(x)
    $*)
  elsif !x['if'] && x[0] != 'f'
    y = x[0...x.index('for')]
    x = x[x.index('for')..-1]
    (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
    x.insert(x.length, "end; $*")
    eval(x)
    $*)
  else
    eval(x.split[3]).to_a
  end
end 

সুতরাং মূলত আমরা একটি স্ট্রিংটিকে লুপের জন্য যথাযথ রুবি সিনট্যাক্সে রূপান্তর করছি তবে আমরা স্ট্রিংয়ের ক্ষেত্রে পাইথন সিনট্যাক্সটি ব্যবহার করতে পারি:

c['for x in 1..10']
c['for x in 1..10 if x.even?']
c['x**2 for x in 1..10 if x.even?']
c['x**2 for x in 1..10']

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [2, 4, 6, 8, 10]
# [4, 16, 36, 64, 100]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

অথবা আপনি যদি স্ট্রিংটি দেখতে পছন্দ করেন না বা ল্যাম্বডা ব্যবহার করতে চান তা না হলে আমরা পাইথন সিনট্যাক্সকে মিরর করার চেষ্টা করতে পারি এবং এরকম কিছু করতে পারি:

S = [for x in 0...9 do $* << x*2 if x.even? end, $*][1]
# [0, 4, 8, 12, 16]

0

রুবি ২.7 চালু করেছে filter_mapযা আপনি যা চান তা অর্জন করে (মানচিত্র + কমপ্যাক্ট):

some_array.filter_map { |x| x * 3 if x % 2 == 0 }

আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন ।



-4

আমি মনে করি সর্বাধিক তালিকা অনুধাবন-এসকেই নিম্নলিখিত হবে:

some_array.select{ |x| x * 3 if x % 2 == 0 }

যেহেতু রুবি আমাদের প্রকাশের পরে শর্তযুক্ত রাখার অনুমতি দেয় তাই আমরা তালিকা বোধের পাইথন সংস্করণের অনুরূপ সিনট্যাক্স পাই। এছাড়াও, যেহেতু selectপদ্ধতিটিতে সমান কোনও কিছু অন্তর্ভুক্ত করা হয় না false, ফলস্বরূপ তালিকা থেকে সমস্ত শূন্য মানগুলি সরিয়ে ফেলা হয় এবং আমরা ব্যবহার করা mapবা collectতার পরিবর্তে কমপ্যাক্টের কোনও কল প্রয়োজন হয় না the


7
এটি কাজ করে না। কমপক্ষে রুবিতে 1.8.6, [1,2,3,4,5,6] এ নির্বাচন করুন se | এক্স | x * 3 যদি x% 2 == 0} [2, 4, 6] এর মূল্যায়ণ করে] গণনাযোগ্য # নির্বাচন কেবল ব্লককে সত্য বা মিথ্যা হিসাবে মূল্যায়ন করে কিনা তা বিবেচনা করে, এটির মূল্য কী হবে না, এএফআইএকে।
গ্রেগ ক্যাম্পবেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.