পাইথন তালিকার সমতুল্য সমান করতে, আমি নিম্নলিখিতগুলি করছি:
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