Search code examples
rubyreduceinject

How does using Array#reduce in this way work?


I have been learning ruby for the last few weeks and I came across something like:

array = [10, 20, 20];

array.reduce(:^)

# => 10

which evaluated to 10.

The purpose of the code was to find an element with an odd number of occurrences within a sequence such as [10, 20, 20].

Does anyone have a relatively simple explanation of how this works?


Solution

  • array = [10, 20, 20];
    
    array.reduce(:^)
      #=> 10
    

    produces the same result as

    array.reduce { |t,n| t^n }
      #=> 10
    

    Let's add a puts statement to see what is happening.

    array.reduce do |t,n|
      puts "t = #{t}, n = #{n}, t^n = #{t^n}"
      t^n
    end
      # t = 10, n = 20, t^n = 30
      # t = 30, n = 20, t^n = 10
      #=> 10
    

    When Enumerable#reduce is not given an argument the "memo" (the block variablet) is set equal to the first element of the receiver (10) and the first element passed to the block is the second element of the receiver, 20.

    Fixnum#^ is the bitwise "exclusive-or" operator (XOR).

    When t #=> 10 and (the first) n #=> 20 is passed to the block:

    t^n #=> 30
    

    because

    10.to_s(2)      #=> "01010" 
    20.to_s(2)      #=> "10100"
                         ----- 
    (10^20).to_s(2) #=> "11110"
    "11110".to_i(2) #=>     30
    10^20           #=>     30
    

    When t #=> 30 and (the second) n #=> 20 is passed to the block:

    t^n #=> 10
    

    because

    30.to_s(2)      #=> "11110" 
    20.to_s(2)      #=> "10100" 
                         ----- 
    (30^20).to_s(2) #=> "01010" 
    "1010".to_i(2)  #=>     10     
    (30^20)         #=>     10