পাইথন তালিকার সমতুল্য সমান করতে, আমি নিম্নলিখিতগুলি করছি:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
এটি করার আরও ভাল উপায় আছে ... সম্ভবত একটি পদ্ধতি কল দিয়ে?
পাইথন তালিকার সমতুল্য সমান করতে, আমি নিম্নলিখিতগুলি করছি:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
এটি করার আরও ভাল উপায় আছে ... সম্ভবত একটি পদ্ধতি কল দিয়ে?
উত্তর:
আপনি যদি সত্যিই চান, আপনি এটির মতো একটি অ্যারে # অনুধাবন পদ্ধতি তৈরি করতে পারেন:
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
আপনি সম্ভবত এটিই করতেন।
[nil, nil, nil].comprehend {|x| x }যা প্রত্যাবর্তন করে []।
compact!কোনও আইটেম পরিবর্তন করা না গেলে অ্যারের পরিবর্তে শূন্য ফেরত দেয়, তাই আমি মনে করি না এটি কাজ করে।
কীভাবে:
some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact
কমপক্ষে আমার স্বাদ থেকে খানিকটা ক্লিনার, এবং আপনার সংস্করণের চেয়ে প্রায় 15% দ্রুত দ্রুত বেনমার্ক পরীক্ষা অনুযায়ী ...
some_array.map{|x| x * 3 unless x % 2}.compact, যা তর্কযোগ্যভাবে আরও পঠনযোগ্য / রুবি-এস্কো।
unless x%2কোনও প্রভাব নেই। দেখুন: gist.github.com/jfarmer/2647362
আমি তিনটি বিকল্প এবং মানচিত্র-কমপ্যাক্টের তুলনায় একটি দ্রুত বেঞ্চমার্ক তৈরি করেছি যা সত্যিই সেরা বিকল্প বলে মনে হচ্ছে।
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
তালিকা অনুধাবন কী তা নিয়ে এই থ্রেডে রুবি প্রোগ্রামারদের মধ্যে কিছু বিভ্রান্তি রয়েছে বলে মনে হয়। প্রতিটি একক প্রতিক্রিয়া রূপান্তরিত করার জন্য কিছু পূর্বনির্মাণ অ্যারে ধরে নেয়। তবে তালিকাটি বোঝার শক্তি নীচের বাক্য গঠন সহ ফ্লাইতে তৈরি একটি অ্যারেতে রয়েছে:
squares = [x**2 for x in range(10)]
নিম্নলিখিতটি রুবিতে একটি এনালগ হবে (এই থ্রেডের একমাত্র পর্যাপ্ত উত্তর, এএফএসি):
a = Array.new(4).map{rand(2**49..2**50)}
উপরের ক্ষেত্রে, আমি এলোমেলো পূর্ণসংখ্যার একটি অ্যারে তৈরি করছি, তবে ব্লকটিতে কিছু থাকতে পারে। তবে এটি রুবি তালিকার বোঝাপড়া হবে।
আমি এই বিষয়টিকে নিয়ে রেন হেনরিচের সাথে আলোচনা করেছি, যিনি আমাকে বলেন যে সবচেয়ে ভাল পারফরম্যান্স সমাধান solution
map { ... }.compact
এটি সুবোধ তৈরি করে কারণ এটি অপরিবর্তনীয় ব্যবহারের মতো মধ্যবর্তী অ্যারে তৈরি করা Enumerable#injectএড়িয়ে যায় এবং এটি অ্যারে বৃদ্ধি করা এড়ায়, যা বরাদ্দ সৃষ্টি করে। এটি অন্য কারোর মতোই সাধারণ, যদি না আপনার সংগ্রহে শূন্য উপাদান থাকতে পারে।
আমি এর সাথে তুলনা করি না
select {...}.map{...}
এটি সম্ভব যে রুবির সি বাস্তবায়নও Enumerable#selectখুব ভাল।
একটি বিকল্প সমাধান যা প্রতিটি প্রয়োগে কাজ করে এবং ও (2 এন) সময়ের পরিবর্তে ও (এন) এ চালিত হয় তা হ'ল:
some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}
2জিনিষ nপরিবর্তে বার 1জিনিস nবার এবং তারপর অন্য 1জিনিস nবার :) এক গুরুত্বপূর্ণ সুবিধা inject/ reduceএটি কোন সংরক্ষিত কিতাব nilইনপুট ক্রম যা প্রায়ই তালিকা-comprehensionly আচরণ মান
আমি সবেমাত্র রুবিগেমসকে বোঝার রত্ন প্রকাশ করেছি , যা আপনাকে এটি করতে দেয়:
require 'comprehend'
some_array.comprehend{ |x| x * 3 if x % 2 == 0 }
এটি সিতে লেখা; অ্যারেটি কেবল একবার ট্র্যাভার করা হয়।
গণনার একটি grepপদ্ধতি রয়েছে যার প্রথম তর্কটি প্রিকিকেট প্রোক হতে পারে এবং যার বিকল্প argument চ্ছিক দ্বিতীয় যুক্তি একটি ম্যাপিং ফাংশন; সুতরাং নিম্নলিখিত কাজ করে:
some_array.grep(proc {|x| x % 2 == 0}) {|x| x*3}
এটি অন্যান্য কয়েকটি পরামর্শের মতো পঠনযোগ্য নয় (আমি অ্যানোইয়াকের সহজ select.mapবা হিস্ট্রোক্রেটের বোঝার রত্নটি পছন্দ করি) তবে এর শক্তিগুলি এটি ইতিমধ্যে স্ট্যান্ডার্ড লাইব্রেরির অংশ, এবং একক-পাস এবং অস্থায়ী মধ্যবর্তী অ্যারে তৈরি করার সাথে জড়িত না , এবং nilব্যবহারের compactপরামর্শগুলিতে ব্যবহারের মতো সীমার বাইরে মান প্রয়োজন হয় না ।
এটি আরও সংক্ষিপ্ত:
[1,2,3,4,5,6].select(&:even?).map{|x| x*3}
[1,2,3,4,5,6].select(&:even?).map(&3.method(:*))
ভালো লেগেছে পেড্রো উল্লেখ করা হয়েছে, আপনাকে শৃঙ্খলিত কল একসঙ্গে দ্রব করতে Enumerable#selectএবং Enumerable#mapনির্বাচিত উপাদানের উপর একটি ট্র্যাভেরসাল এড়ানো। এটি সত্য কারণ Enumerable#selectভাঁজ বা এর একটি বিশেষীকরণ inject। আমি রুবি সাব্রেডডিটে এই বিষয়টির তাত্ক্ষণিক পরিচয় পোস্ট করেছি ।
অ্যারে রূপান্তরগুলি ম্যানুয়ালি ফিউজ করা বিরক্তিকর হতে পারে, তাই সম্ভবত কেউ comprehendএই select/ mapপ্যাটার্নটিকে সুন্দর করার জন্য রবার্ট গাম্বলের প্রয়োগের সাথে খেলতে পারে ।
এটার মতো কিছু:
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?}
আর একটি সমাধান তবে সম্ভবত সেরা নয়
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 }
এটির কাছে যাওয়ার এই এক উপায়:
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]
রুবি ২.7 চালু করেছে filter_mapযা আপনি যা চান তা অর্জন করে (মানচিত্র + কমপ্যাক্ট):
some_array.filter_map { |x| x * 3 if x % 2 == 0 }
আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন ।
https://rubygems.org/gems/ruby_list_comprehension
অভিজাত রুবি তালিকা বোঝার অনুমতি দেওয়ার জন্য আমার রুবি তালিকার সমঝোতার রত্নের জন্য নির্লজ্জ প্লাগ
$l[for x in 1..10 do x + 2 end] #=> [3, 4, 5 ...]
আমি মনে করি সর্বাধিক তালিকা অনুধাবন-এসকেই নিম্নলিখিত হবে:
some_array.select{ |x| x * 3 if x % 2 == 0 }
যেহেতু রুবি আমাদের প্রকাশের পরে শর্তযুক্ত রাখার অনুমতি দেয় তাই আমরা তালিকা বোধের পাইথন সংস্করণের অনুরূপ সিনট্যাক্স পাই। এছাড়াও, যেহেতু selectপদ্ধতিটিতে সমান কোনও কিছু অন্তর্ভুক্ত করা হয় না false, ফলস্বরূপ তালিকা থেকে সমস্ত শূন্য মানগুলি সরিয়ে ফেলা হয় এবং আমরা ব্যবহার করা mapবা collectতার পরিবর্তে কমপ্যাক্টের কোনও কল প্রয়োজন হয় না the