রুবিতে কীভাবে একটি অ্যারে সাজানো যায় তা সাজানো


282

আমার কাছে হ্যাশগুলির একটি অ্যারে রয়েছে:

[
  { :foo => 'foo', :bar => 2 },
  { :foo => 'foo', :bar => 3 },
  { :foo => 'foo', :bar => 5 },
]

আমি এই অ্যারের মান অনুসারে অবতরণ ক্রমে সাজানোর চেষ্টা করছি :bar প্রতিটি হ্যাশের ।

আমি sort_byউপরে অ্যারে বাছাই করতে ব্যবহার করছি :

a.sort_by { |h| h[:bar] }

যাইহোক, এটি আরোহী ক্রমে অ্যারে বাছাই করে। আমি কীভাবে এটি সাজানো ক্রম অনুসারে সাজিয়ে তুলব?

একটি সমাধান নিম্নলিখিত করা ছিল:

a.sort_by { |h| -h[:bar] }

তবে negativeণাত্মক চিহ্নটি যথাযথ বলে মনে হয় না।


4
অন্যান্য বিকল্পগুলি দিয়েছি যা আমি এখনও ভাবি - [[বার]] সবচেয়ে মার্জিত। আপনি এটি সম্পর্কে কি পছন্দ করেন না?
মাইকেল কোহল

2
আমি কোডের অভিপ্রায় জানাতে আরও আগ্রহী ছিলাম।
ওয়াসিম

1
@ ওয়াসিম আমি কি আপনাকে গৃহীত উত্তরটি আপডেট করতে সমস্যায় ফেলতে পারি?
কল্লিন

7
@ ওয়াসিম বর্তমান উত্তরের সাথে কোন ভুল নেই। এর চেয়ে আরও ভাল উত্তর হতে পারে। টিন ম্যানের উত্তরটি আরও পুরোপুরি এবং sort_by.reverseএটি বর্তমানে গৃহীত উত্তরের চেয়ে নাটকীয়ভাবে আরও দক্ষ is আমি বিশ্বাস করি এটি "কোডের অভিপ্রায় জানাতে" আপনার উপরে উল্লিখিত উদ্বেগকে আরও ভালভাবে সমাধান করে। তার উপরে, টিন ম্যান রুবির বর্তমান সংস্করণটির জন্য তার উত্তর আপডেট করেছে। এই প্রশ্নটি 15k বার দেখা হয়েছে। আপনি যদি প্রতিটি দর্শকের সময়ের 1 সেকেন্ডও সঞ্চয় করতে পারেন তবে আমার মনে হয় এটির পক্ষে এটি উপযুক্ত।
কল্লিন

3
ক্যালিন্ডো ধন্যবাদ আমি এটি করেছি। :)
ওয়াসিম

উত্তর:


566

বিভিন্ন প্রস্তাবিত উত্তরের একটি মানদণ্ড করা সর্বদা আলোকিত করা। আমি যা জানতে পেরেছি তা এখানে:

#! / Usr / bin / রুবি

'বেঞ্চমার্ক' প্রয়োজন

ary = []
1000.টাইমস { 
  ary << {: বার => র‌্যান্ড (1000)} 
}

n = 500
বেঞ্চমার্ক.বিএম (20) কর | এক্স |
  x.report ("সাজান") {n.টাইমস {ary.sort {| ক, খ | বি [: বার] <=> এ [: বার]}}}
  x.report ("সাজানো বিপরীত") {n.টাইমস {ary.sort {| ক, খ | a [: বার] <=> খ [: বার]}। বিপরীত}
  x.report ("সাজানো_বাইএ [বার:" ") {n.টাইমস {আরি.সোর্ট_বাই {| আ | -একটি বার] } } }
  x.report ("সাজানো_এক [: বার] * - 1") {n.টাইমস {ary.sort_by {| a | a [: বার] * - 1}}}
  x.report ("sort_by.revers!") {n.টাইমস {ary.sort_by {| a | একটি [: বার] re। বিপরীত}
শেষ

                          ব্যবহারকারী সিস্টেম মোট বাস্তব
বাছাই করুন 3.960000 0.010000 3.970000 (3.990886)
বাছাই করুন 4.040000 0.000000 4.040000 (4.038849)
সাজানো_বি -a [: বার] 0.690000 0.000000 0.690000 (0.692080)
বাছাই_এক [: বার] * - 1 0.700000 0.000000 0.700000 (0.699735)
sort_by.reverse! 0.650000 0.000000 0.650000 (0.654447)

আমি মনে করি এটি আকর্ষণীয় যে @ পাবলো sort_by{...}.reverse!দ্রুততম। পরীক্ষা চালানোর আগে আমি ভেবেছিলাম এটি " -a[:bar]" এর চেয়ে ধীর হবে তবে মানটিকে অগ্রাহ্য করার ফলে এটি একটি পাসে পুরো অ্যারেটিকে উল্টে যাওয়ার চেয়ে বেশি সময় নেয় to এটি খুব বেশি পার্থক্য নয়, তবে প্রতিটি সামান্য গতি বাড়িয়ে তোলে।


দয়া করে মনে রাখবেন যে রুবি ১.৯-এ এই ফলাফলগুলি পৃথক

রুবি 1.9.3p194 (2012-04-20 রিভিশন 35410) এর জন্য ফলাফল এখানে রয়েছে [x86_64-darwin10.8.0]:

                           user     system      total        real
sort                   1.340000   0.010000   1.350000 (  1.346331)
sort reverse           1.300000   0.000000   1.300000 (  1.310446)
sort_by -a[:bar]       0.430000   0.000000   0.430000 (  0.429606)
sort_by a[:bar]*-1     0.420000   0.000000   0.420000 (  0.414383)
sort_by.reverse!       0.400000   0.000000   0.400000 (  0.401275)

এগুলি পুরানো ম্যাকবুক প্রোতে রয়েছে। আরও নতুন বা দ্রুত মেশিনগুলির মান কম হবে, তবে আপেক্ষিক পার্থক্য থাকবে।


এখানে নতুন হার্ডওয়্যারটির সামান্য আপডেট হওয়া সংস্করণ এবং রুবির ২.১.১ সংস্করণ রয়েছে:

#!/usr/bin/ruby

require 'benchmark'

puts "Running Ruby #{RUBY_VERSION}"

ary = []
1000.times {
  ary << {:bar => rand(1000)}
}

n = 500

puts "n=#{n}"
Benchmark.bm(20) do |x|
  x.report("sort")               { n.times { ary.dup.sort{ |a,b| b[:bar] <=> a[:bar] } } }
  x.report("sort reverse")       { n.times { ary.dup.sort{ |a,b| a[:bar] <=> b[:bar] }.reverse } }
  x.report("sort_by -a[:bar]")   { n.times { ary.dup.sort_by{ |a| -a[:bar] } } }
  x.report("sort_by a[:bar]*-1") { n.times { ary.dup.sort_by{ |a| a[:bar]*-1 } } }
  x.report("sort_by.reverse")    { n.times { ary.dup.sort_by{ |a| a[:bar] }.reverse } }
  x.report("sort_by.reverse!")   { n.times { ary.dup.sort_by{ |a| a[:bar] }.reverse! } }
end

# >> Running Ruby 2.1.1
# >> n=500
# >>                            user     system      total        real
# >> sort                   0.670000   0.000000   0.670000 (  0.667754)
# >> sort reverse           0.650000   0.000000   0.650000 (  0.655582)
# >> sort_by -a[:bar]       0.260000   0.010000   0.270000 (  0.255919)
# >> sort_by a[:bar]*-1     0.250000   0.000000   0.250000 (  0.258924)
# >> sort_by.reverse        0.250000   0.000000   0.250000 (  0.245179)
# >> sort_by.reverse!       0.240000   0.000000   0.240000 (  0.242340)

আরও সাম্প্রতিক ম্যাকবুক প্রোতে রুবি ২.২.১ ব্যবহার করে উপরের কোডটি চালিত নতুন ফলাফল। আবার, সঠিক সংখ্যাগুলি গুরুত্বপূর্ণ নয়, এটি তাদের সম্পর্ক:

Running Ruby 2.2.1
n=500
                           user     system      total        real
sort                   0.650000   0.000000   0.650000 (  0.653191)
sort reverse           0.650000   0.000000   0.650000 (  0.648761)
sort_by -a[:bar]       0.240000   0.010000   0.250000 (  0.245193)
sort_by a[:bar]*-1     0.240000   0.000000   0.240000 (  0.240541)
sort_by.reverse        0.230000   0.000000   0.230000 (  0.228571)
sort_by.reverse!       0.230000   0.000000   0.230000 (  0.230040)

মিড-2015 ম্যাকবুক প্রোতে রুবি 2.7.1 এর জন্য আপডেট হয়েছে:

Running Ruby 2.7.1
n=500     
                           user     system      total        real
sort                   0.494707   0.003662   0.498369 (  0.501064)
sort reverse           0.480181   0.005186   0.485367 (  0.487972)
sort_by -a[:bar]       0.121521   0.003781   0.125302 (  0.126557)
sort_by a[:bar]*-1     0.115097   0.003931   0.119028 (  0.122991)
sort_by.reverse        0.110459   0.003414   0.113873 (  0.114443)
sort_by.reverse!       0.108997   0.001631   0.110628 (  0.111532)

... বিপরীত পদ্ধতিটি আসলে একটি বিপরীত অ্যারে ফিরিয়ে দেয় না - এটি এমন একটি গণক দেয় যা কেবল শেষে শুরু হয় এবং পিছনের দিকে কাজ করে।

এর উত্স Array#reverseহ'ল:

               static VALUE
rb_ary_reverse_m(VALUE ary)
{
    long len = RARRAY_LEN(ary);
    VALUE dup = rb_ary_new2(len);

    if (len > 0) {
        const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary);
        VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
        do *p2-- = *p1++; while (--len > 0);
    }
    ARY_SET_LEN(dup, RARRAY_LEN(ary));
    return dup;
}

do *p2-- = *p1++; while (--len > 0); আমি যদি আমার সি সঠিকভাবে মনে করি তবে অ্যারেটি বিপরীত হয় তাই বিপরীত ক্রমে উপাদানগুলিতে পয়েন্টারগুলি অনুলিপি করা হয়।


45
সুপার দরকারী। অতিরিক্ত প্রচেষ্টা করার জন্য ধন্যবাদ।
জোশুয়া পিন্টার 25'12

7
আমি এটি পছন্দ করি যখন লোকেরা এই জাতীয় মানদণ্ড প্রমাণ সরবরাহ করে !! অসাধারণ!
ktec

25
"লোকেরা যখন এই জাতীয় মানদণ্ড প্রমাণ সরবরাহ করে তখন আমি এটি পছন্দ করি!" আমিও করি, কারণ তখন আমার দরকার নেই।
টিন ম্যান

9
@ থিনমান আপনি কি আপনার উত্তরের জন্য একটি টিএল; ডিআর সরবরাহ করতে পারেন? এই সমস্ত মানদণ্ডের তথ্য বেশ কার্যকর। তবে উত্তরের উপরে একটি টিএল; ডিআর সেই লোকদের জন্য কার্যকর হবে যারা কেবল উত্তরটি চান। আমি জানি তাদের পুরো ব্যাখ্যাটি পড়া উচিত এবং আমি মনে করি তারা তা করবে। এখনও একটি টিএল; ডিআর আইএমএইচও বেশ কার্যকর হবে। আপনার প্রচেষ্টার জন্য ধন্যবাদ.
ওয়াসিম

8
আমি @ ওয়াসিমের সাথে একমত এই উত্তরটির মতো যথাযথ গবেষণা করা হয়েছে, ওপি "রুবিতে একটি উতরাই বাছাইয়ের সবচেয়ে দ্রুত উপায় কী" জিজ্ঞাসা করেনি। শীর্ষে একটি টিএল; ডিআর সহজ ব্যবহারগুলি দেখায়, মাপদণ্ড অনুসরণ করে, এই উত্তরটি আইএমওতে উন্নত করবে improve

89

কেবলমাত্র একটি দ্রুত জিনিস, এটি অবতরণ ক্রমের উদ্দেশ্যটিকে বোঝায়।

descending = -1
a.sort_by { |h| h[:bar] * descending }

(গড় সময়ে একটি ভাল উপায় সম্পর্কে চিন্তা করবে);)


a.sort_by { |h| h[:bar] }.reverse!

পাবলো, আরও ভাল উপায় খুঁজে নেওয়ার জন্য দুর্দান্ত কাজ! আমি যে মানদণ্ডটি করেছি তা দেখুন।
টিন ম্যান

প্রথম পদ্ধতিটি দ্রুত (যদিও কুশ্রী হতে পারে) কারণ এটি কেবল একবার লুপ করে। দ্বিতীয় হিসাবে, আপনার প্রয়োজন নেই! এটি ইনপ্লেস অপারেশনগুলির জন্য।
টোকল্যান্ড

3
বিপরীত পরে আপনি যদি ব্যাং ব্যবহার না করেন আপনি অ্যারেটিকে বিপরীত করবেন না বরং বিপরীত অন্যটি তৈরি করবেন।
পাবলো ফার্নান্দেজ

56

আপনি করতে পারেন:

a.sort{|a,b| b[:bar] <=> a[:bar]}

4
তবে ব্যবহারের পুরো sort_by
বিষয়টিটি

3
-1। sort_byএটি অনেক বেশি দক্ষ এবং আরও পাঠযোগ্য। মান অবহেলা করা বা শেষে একটি বিপরীত করা দ্রুত এবং আরও পঠনযোগ্য হবে।
মার্ক-অ্যান্ড্রে লাফোর্টুন

1
আমি এই উত্তরটি পছন্দ করি কারণ * -1সমস্ত মান (যেমন সময়) এর সাথে কাজ করে না, এবং reverseসমান হিসাবে সাজানো মানগুলি পুনরায় অর্ডার করবে
আবে ভোলেকার

8

আমি দেখতে পাচ্ছি যে আমাদের কাছে (অন্যদের পাশে) মূলত দুটি বিকল্প রয়েছে:

a.sort_by { |h| -h[:bar] }

এবং

a.sort_by { |h| h[:bar] }.reverse

আপনার বাছাই করা কীটি অনন্য যখন উভয় উপায়েই আপনাকে একই ফল দেয়, মনে রাখবেন যে উপায়টি সমান কীগুলির ক্রমটিকে বিপরীতreverse করবে ।

উদাহরণ:

a = [{foo: 1, bar: 1},{foo: 2,bar: 1}]
a.sort_by {|h| -h[:bar]}
 => [{:foo=>1, :bar=>1}, {:foo=>2, :bar=>1}]
a.sort_by {|h| h[:bar]}.reverse
 => [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]

আপনার প্রায়শই এটির যত্ন নেওয়ার প্রয়োজন নেই, কখনও কখনও আপনি এটি করেন। এই জাতীয় আচরণ এড়াতে আপনি একটি দ্বিতীয় বাছাই কী প্রবর্তন করতে পারেন (এটি নিশ্চিত যে কমপক্ষে সমস্ত বাছাইয়ের কী রয়েছে এমন সমস্ত আইটেমের জন্য স্বতন্ত্র হওয়া দরকার):

a.sort_by {|h| [-h[:bar],-h[:foo]]}
 => [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]
a.sort_by {|h| [h[:bar],h[:foo]]}.reverse
 => [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]

+1 এর নির্দেশকটির জন্য শব্দার্থক শব্দগুলি reverseআলাদা। আমি বিশ্বাস করি এটি পূর্ববর্তী ধরণের সমস্যারও জগাখিচুড়ি করবে, যেখানে কেউ একরকমভাবে যাতে একাধিক ক্রমে একাধিক প্রকার প্রয়োগ করার চেষ্টা করছে।
জনসিপ

6

কি সম্পর্কে:

 a.sort {|x,y| y[:bar]<=>x[:bar]}

এটি কাজ করে !!

irb
>> a = [
?>   { :foo => 'foo', :bar => 2 },
?>   { :foo => 'foo', :bar => 3 },
?>   { :foo => 'foo', :bar => 5 },
?> ]
=> [{:bar=>2, :foo=>"foo"}, {:bar=>3, :foo=>"foo"}, {:bar=>5, :foo=>"foo"}]

>>  a.sort {|x,y| y[:bar]<=>x[:bar]}
=> [{:bar=>5, :foo=>"foo"}, {:bar=>3, :foo=>"foo"}, {:bar=>2, :foo=>"foo"}]

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

যদিও sortইচ্ছা কাজ, এটি শুধুমাত্র দ্রুততর যখন তাৎক্ষণিক মান বাছাই আছে। আপনি তাদের জন্য খনন করতে sort_byহয় দ্রুত। মানদণ্ড দেখুন।
টিন ম্যান

3

উল্লিখিত মাপদণ্ডের স্যুট সম্পর্কে, এই ফলাফলগুলি বাছাই করা অ্যারেগুলির জন্যও ধারণ করে।

sort_by/ reverseএটি হল:

# foo.rb
require 'benchmark'

NUM_RUNS = 1000

# arr = []
arr1 = 3000.times.map { { num: rand(1000) } }
arr2 = 3000.times.map { |n| { num: n } }.reverse

Benchmark.bm(20) do |x|
  { 'randomized'     => arr1,
    'sorted'         => arr2 }.each do |label, arr|
    puts '---------------------------------------------------'
    puts label

    x.report('sort_by / reverse') {
      NUM_RUNS.times { arr.sort_by { |h| h[:num] }.reverse }
    }
    x.report('sort_by -') {
      NUM_RUNS.times { arr.sort_by { |h| -h[:num] } }
    }
  end
end

এবং ফলাফল:

$: ruby foo.rb
                           user     system      total        real
---------------------------------------------------
randomized
sort_by / reverse      1.680000   0.010000   1.690000 (  1.682051)
sort_by -              1.830000   0.000000   1.830000 (  1.830359)
---------------------------------------------------
sorted
sort_by / reverse      0.400000   0.000000   0.400000 (  0.402990)
sort_by -              0.500000   0.000000   0.500000 (  0.499350)

আপনার বাছাই_সেব {} করতে সক্ষম হওয়া উচিত। বিপরীত! (ঠুং ঠুং শব্দ ছাড়াই বিপরীত একটি নতুন অ্যারে তৈরি করে এবং আমি আশা করি এটি অবশ্যই ধীর হবে)
বিবিস্তাপ

2

আরোহণ থেকে অবতরণ এবং বিপরীত দিকে সরল সমাধানটি হ'ল:

স্ট্রিং

str = ['ravi', 'aravind', 'joker', 'poker']
asc_string = str.sort # => ["aravind", "joker", "poker", "ravi"]
asc_string.reverse # => ["ravi", "poker", "joker", "aravind"]

ডিজিটের

digit = [234,45,1,5,78,45,34,9]
asc_digit = digit.sort # => [1, 5, 9, 34, 45, 45, 78, 234]
asc_digit.reverse # => [234, 78, 45, 45, 34, 9, 5, 1]

1

যারা ভাবেন তাদের জন্য যারা আইপিএসের গতি মাপতে পছন্দ করেন;)

require 'benchmark/ips'

ary = []
1000.times { 
  ary << {:bar => rand(1000)} 
}

Benchmark.ips do |x|
  x.report("sort")               { ary.sort{ |a,b| b[:bar] <=> a[:bar] } }
  x.report("sort reverse")       { ary.sort{ |a,b| a[:bar] <=> b[:bar] }.reverse }
  x.report("sort_by -a[:bar]")   { ary.sort_by{ |a| -a[:bar] } }
  x.report("sort_by a[:bar]*-1") { ary.sort_by{ |a| a[:bar]*-1 } }
  x.report("sort_by.reverse!")   { ary.sort_by{ |a| a[:bar] }.reverse }
  x.compare!
end

এবং ফলাফল:

Warming up --------------------------------------
                sort    93.000  i/100ms
        sort reverse    91.000  i/100ms
    sort_by -a[:bar]   382.000  i/100ms
  sort_by a[:bar]*-1   398.000  i/100ms
    sort_by.reverse!   397.000  i/100ms
Calculating -------------------------------------
                sort    938.530   1.8%) i/s -      4.743k in   5.055290s
        sort reverse    901.157   6.1%) i/s -      4.550k in   5.075351s
    sort_by -a[:bar]      3.814k  4.4%) i/s -     19.100k in   5.019260s
  sort_by a[:bar]*-1      3.732k  4.3%) i/s -     18.706k in   5.021720s
    sort_by.reverse!      3.928k  3.6%) i/s -     19.850k in   5.060202s

Comparison:
    sort_by.reverse!:     3927.8 i/s
    sort_by -a[:bar]:     3813.9 i/s - same-ish: difference falls within error
  sort_by a[:bar]*-1:     3732.3 i/s - same-ish: difference falls within error
                sort:      938.5 i/s - 4.19x  slower
        sort reverse:      901.2 i/s - 4.36x  slower
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.