2016-04-30 17 views
0

以下のコードは私の初心者のバブルソート方法です。どのようにブロックを「バブルソート」メソッドに渡すことができますか?

#For each element in the list, look at that element and the element 
#directly to it's right. Swap these two elements so they are in 
#ascending order. 

def bubble_sort (array) 
    a = 0 
    b = 1 
    until (array.each_cons(2).all? { |a, b| (a <=> b) <= 0}) == true do 
     sort = lambda {array[a] <=> array[b]} 
     sort_call = sort.call 
     loop do 
      case sort_call 
      when -1 #don't swap 
       a += 1 
       b += 1 
       break 
      when 0 #don't swap 
       a += 1 
       b += 1 
       break 
      when 1 #swap 
       array.insert(a,array.delete_at(b)) 
       a += 1 
       b += 1 
       break 
      else #end of array, return to start 
       a = 0 
       b = 1 
       break 
      end 
     end 
    end 
    puts array.inspect 
end 

array = [4, 2, 5, 6, 3, 23, 5546, 234, 234, 6] 
bubble_sort(array) 

このメソッドを変更して、コードブロックを引数として受け取り、そのソート方法を判断することができます。例えば

array = ["hello", "my", "name", "is", "daniel"] bubble_sort(array) {array[@a].length <=> array[@b].length}

(私はこれを試してみたとき、私は、コード全体でインスタンス変数にabになってきました。)

私はyieldを使用して試してみましたが、私はundefined method 'length' for nil:NilClass一度に取得します配列の終わりに達する。私は、このような

if array[@b+1] == nil 
    @a = 0 
    @b = 1 
end 

これは役立ちますが、私はまだ無限ループまたは要素の一定量以上を並べ替えることができないような奇妙な問題で終わるようなものに追加しようとしました。

短いストーリーですが、私はこれまで数時間でした。私がやりたいことをする簡単な方法はありますか?ありがとう。

答えて

1

ラムダと呼ばれる方法はちょっと奇妙です。実際はまったく必要ありません。私はあなたのコードをリファクタリングし、少し冗長性を取り除いた。私にとっては、次の作品:

def sorted?(arr) 
    arr.each_cons(2).all? { |a, b| (a <=> b) <= 0 } 
end 

def bubble_sort (arr) 
    a = 0 
    b = 1 
    until sorted?(arr) do 
    # The yield call here passes `arr[a]` and `arr[b]` to the block. 
    comparison = if block_given? 
       yield(arr[a], arr[b]) 
      else 
       arr[a] <=> arr[b] 
      end 

    if [-1, 0, 1].include? comparison 
     arr.insert(a, arr.delete_at(b)) if comparison == 1 

     a += 1 
     b += 1 
    else 
     a = 0 
     b = 1 
    end 
    end 

    arr 
end 

sample_array = [4, 2, 5, 6, 3, 23, 5546, 234, 234, 6] 

# Sanity check: 
100.times do 
    # `a` is the value of `arr[a]` in our function above. Likewise for `b` and `arr[b]`. 
    print bubble_sort(sample_array.shuffle) { |a, b| a <=> b }, "\n" 
end 

EDIT

クリーナーバージョンは:

# In place swap will be more efficient as it doesn't need to modify the size of the arra 
def swap(arr, idx) 
    raise IndexError.new("Index #{idx} is out of bounds") if idx >= arr.length || idx < 0 

    temp   = arr[idx] 
    arr[idx]  = arr[idx + 1] 
    arr[idx + 1] = temp 
end 

def bubble_sort(arr) 
    loop do 
    sorted_elements = 0 

    arr.each_cons(2).each_with_index do |pair, idx| 
     comparison = if block_given? 
        yield pair.first, pair.last 
        else 
        pair.first <=> pair.last 
        end 

     if comparison > 0 
     swap(arr, idx) 
     else 
     sorted_elements += 1 
     end 
    end 

    return arr if sorted_elements >= arr.length - 1 
    end 
end 

# A simple test 

sample_array  = [4, 2, 2, 2, 2, 2, 5, 5, 6, 3, 23, 5546, 234, 234, 6] 
sample_str_array = ["a", "ccc", "ccccc"] 

100.times do 
    print bubble_sort(sample_array.shuffle) { |a, b| a <=> b }, "\n" 
    print bubble_sort(sample_str_array.shuffle) { |a, b| a.length <=> b.length }, "\n" 
end 
+0

これはすばらしく、はるかにクリーナーです。ありがとうございます。私が抱えている唯一の問題は、別の議論を通していることです。すなわち、方法自体を変更することなく、単語を長さでソートする。だから、 '' bubble_sort(["This"、 "is"、 "my"、 "array"]){| a、b | a.length <=> b.length)} '毎回メソッドを変更したり変更したりすることなく、ここでそれを行うことができますか?私は毎回行く必要があり、毎回「ソート?」を変更する必要があるように感じる。何とかそこにブロックをつけることはできますか?私はここに投稿する前に何か似たようなことをしようとしていましたが、 '<= 0'も必要なので、' yield 'を働かせることができませんでした。 –

+0

はい、よりクリーンで信頼性の高いソリューションで私の編集を参照してください –

1

あなたはあまり遠く離れていません。ただ、いくつかのこと:

  1. は、ユーザーが

    if block_given? 
        # Call user's comparator block 
    else 
        # Use the default behavior 
    end 
    
  2. は、ユーザーのコンパレータブロックを呼び出すブロックを提供しているかどうかを確認するために、あなたの関数がブロック引数を取る

    def bubble_sort (array, &block) 
    
  3. チェックしてください

    block.call(a, b) 
    
  4. ユーザー提供のブロックで
  5. 、右の球場であなたを置くべきであると

    bubble_sort(array) {|a,b| a.length <=> b.length} 
    

を比較するために、要素のためのブロックのparamsを受け入れます。

+0

あなたは実際に代わり、明示的に '' yield'&block'引数を使用することができます。 'yield'を指定すると、ブロックは暗黙的に渡され、呼び出されます。 –

関連する問題