Breaking Down the Block

Can someone please explain in plain english how this block treats the
given variables (and values in the array)? I am struggling to understand
the relationship of 't' and 'n' with the array.

class Array
  def sum
    inject(0) {|t,n| t + n}
  end
end
puts [1,2,3].sum

Is 't' effectively labeled as '0' (zero), given the assignment on the
inject method?
What "is" 't' exactly?

···

--
Posted via http://www.ruby-forum.com/.

`my_array.inject(0) {|t,n| t + n}` basically breaks down like:

    t = 0
    my_array.each {|n| t = (t + n) }
    t

Similary, leaving out the inital value, `my_array.inject {|t,n| t +
n}` basically breaks down like:

    t = my_array[0]
    my_array[1..-1].each {|n| t = (t + n) }
    t

What you called 't' (often called the 'memory') is the accumulation,
or the result of the last iteration of the block.

···

On 13 September 2012 12:09, incag neato <lists@ruby-forum.com> wrote:

Can someone please explain in plain english how this block treats the
given variables (and values in the array)? I am struggling to understand
the relationship of 't' and 'n' with the array.

class Array
  def sum
    inject(0) {|t,n| t + n}
  end
end
puts [1,2,3].sum

Is 't' effectively labeled as '0' (zero), given the assignment on the
inject method?
What "is" 't' exactly?

--
Posted via http://www.ruby-forum.com/\.

--
  Matthew Kerwin, B.Sc (CompSci) (Hons)
  http://matthew.kerwin.net.au/
  ABN: 59-013-727-651

  "You'll never find a programming language that frees
  you from the burden of clarifying your ideas." - xkcd

incag neato wrote in post #1075712:

Can someone please explain in plain english how this block treats the
given variables (and values in the array)? I am struggling to understand
the relationship of 't' and 'n' with the array.

class Array
  def sum
    inject(0) {|t,n| t + n}
  end
end
puts [1,2,3].sum

Is 't' effectively labeled as '0' (zero), given the assignment on the
inject method?
What "is" 't' exactly?

Just forget inject() even exists. It's really quite a pathetic method.

···

--
Posted via http://www.ruby-forum.com/\.

Think of it this way:

inject(memo) { | memo, enum | block sets memo } => memo

So memo has three stages:

1. Before the first iteration, memo is set to the value of the parameter
(in parentheses after "inject").

2. After each iteration, the result of the block becomes the new value
of memo.

3. When it's all over, the value of memo is the result.

So it's all about accumulating results into memo. (It is sometimes
called the accumulator.)

In your example, the accumulation involves adding the successive values
of enum to the accumulator. The successive values of enum are the values
of the array. So the result is the sum of the array. (It's the sum of
the array plus the initial value of the memo, but that initial value is
zero, so it really is just the sum.)

m.

···

incag neato <lists@ruby-forum.com> wrote:

Can someone please explain in plain english how this block treats the
given variables (and values in the array)? I am struggling to understand
the relationship of 't' and 'n' with the array.

class Array
  def sum
    inject(0) {|t,n| t + n}
  end
end
puts [1,2,3].sum

Is 't' effectively labeled as '0' (zero), given the assignment on the
inject method?
What "is" 't' exactly?

--
matt neuburg, phd = matt@tidbits.com <http://www.tidbits.com/matt/&gt;
A fool + a tool + an autorelease pool = cool!
AppleScript: the Definitive Guide - Second Edition!
Matt Neuburg’s Home Page

However, with better variable names, it might be clearer what's going on
with inject:

class Array
  def sum1
    inject(0) {|total, array_element| total += array_element}
  end

  def sum2
    total = 0

    self.each do |array_element|
      total += array_element
    end

    total
  end
end

puts [1, 2, 3].sum1
puts [1, 2, 3].sum2

--output:--
6
6

···

--
Posted via http://www.ruby-forum.com/.

Or even better:

class Array
  def sum1
    initial_val_for_total = 0
    inject(initial_val_for_total) {|total, array_element| total +=
array_element}
  end
end

···

--
Posted via http://www.ruby-forum.com/.

This is quite helpful. If we ever meet I owe you each a beer.

In my newbie opinion, Matt Neuburg did a fantastic job above:

Think of it this way:

inject(memo) { | memo, enum | block sets memo } => memo

So memo has three stages:

1. Before the first iteration, memo is set to the value of the parameter
(in parentheses after "inject").

2. After each iteration, the result of the block becomes the new value
of memo.

3. When it's all over, the value of memo is the result.

So it's all about accumulating results into memo. (It is sometimes
called the accumulator.)

What I'm really trying to get at with this question however, is
digesting something more like the following (and yes, I know it gets
slightly more complicated when I introduce a hash..and a map).

def mode(array)
  recur = array.inject(Hash.new(0)) {|k,v| k[v]+=1; k}.sort_by { | (a,b)

-b }

  recur.select { | (a,b) | b == recur[0][1] }.map{ |(a,b) | a }
end

This is meant to find the mode of an array, but I can't understand it
clearly. HELP!

···

--
Posted via http://www.ruby-forum.com/\.

recur = array.inject(Hash.new(0)) {|k,v| k[v]+=1; k}

Horrible variable names are the culprit again.

hash = {}
p hash[10]

--output:--
nil

hash = Hash.new(0)
p hash[10]

--output:--
0

array = [10, 20, 30, 30, 40]

result = array.inject(Hash.new(0)) {|hash, array_element|
hash[array_element] += 1; hash}

p result

--output:--
{10=>1, 20=>1, 30=>2, 40=>1}

···

--
Posted via http://www.ruby-forum.com/\.

z = y.select {|a, b| b == y[0][1]}
p z

--output:--
[[30, 2]]

In this example the conditional b == y[0][1] is equivalent to b == 2.
If instead you had results like this,

[[10, 3], [30, 3], [20, 1], [40, 1]]

...then the conditional would be b == 3, which just selects all the
numbers that tie for the most appearances in the original array.

z = z.map {|a, b| a}
p z

--output:--
[30]

map just selects the first element of all the sub arrays, which are the
numbers that appear the most times in the original array.

···

--
Posted via http://www.ruby-forum.com/.

def mode(array)
  freq_for = Hash.new(0)
  array.each {|number| freq_for[number] += 1}

  nums_with_frequs = freq_for.sort_by {|key, val| -val}
  top_count = nums_with_frequs[0][1]
  most_seen = nums_with_frequs.take_while {|number, freq| freq ==
top_count}

  most_seen.map {|number, freq| number}
end

p mode([10, 10, 10, 20, 30, 30, 40, 40, 40])

--output:--
[10, 40]

···

--
Posted via http://www.ruby-forum.com/.

Sorry, didn't word my question very clearly.
In your previous example, you printed the double mode, [10, 40].
How could you make the program print [40, 10]?

(It's the "b == 3" comment you made that I'm curious about.)
And how it would pertain to this code of yours:

def mode(array)
  freq_for = Hash.new(0)
  array.each {|number| freq_for[number] += 1}

  nums_with_frequs = freq_for.sort_by {|key, val| -val}
  top_count = nums_with_frequs[0][1]
  most_seen = nums_with_frequs.take_while {|number, freq| freq ==
top_count}

  most_seen.map {|number, freq| number}
end

p mode([10, 10, 10, 20, 30, 30, 40, 40, 40])

--output:--
[10, 40]

···

--
Posted via http://www.ruby-forum.com/.

In your previous example, you printed the double mode, [10, 40].
How could you make the program print [40, 10]?

Start at the top of the thread. Read every post, and write down every
method in every post. See if you can't find a method that will do that.

···

--
Posted via http://www.ruby-forum.com/\.

(It's the "b == 3" comment you made that I'm curious about.)

1) If x = 2, then the statement result = x + 4, is equivalent to result
= 6.

2)

the conditional b == y[0][1]
If ... you had results like this,

y = [[10, 3], [30, 3], [20, 1], [40, 1]]

What is y[0][1]? Now plug that value into this conditional:

b == y[0][1]

What do you get?

···

--
Posted via http://www.ruby-forum.com/\.

inject is just reduce/foldl from other languages. It is just sugar for
building an accumulator in a foreach loop, but it has a long history.

···

On Thu, Sep 13, 2012 at 12:46:23PM +0900, 7stud -- wrote:

Just forget inject() even exists. It's really quite a pathetic method.

Sorry, but that's bad practice in best case. #inject doesn't depend on
the total being assigned to by the block; it depends on the value
returned by the block. Your code works, but somebody may be tempted to
do something like adding "p array_element" at the end and suddenly it
breaks for no obvious reason, if somebody believed the assignment was
essential.

-- Matma Rex

···

2012/9/13 7stud -- <lists@ruby-forum.com>:

Or even better:

class Array
  def sum1
    initial_val_for_total = 0
    inject(initial_val_for_total) {|total, array_element| total +=
array_element}
  end
end

However, with better variable names, it might be clearer what's going on
with inject:

class Array
  def sum1
    inject(0) {|total, array_element| total += array_element}
  end

The assignment is totally superfluous.

  def sum2
    total = 0

    self.each do |array_element|
      total += array_element
    end

    total
  end

Here "self." is superfluous. :wink:

Kind regards

robert

···

On Thu, Sep 13, 2012 at 5:55 AM, 7stud -- <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Wow, so helpful. Thanks for taking so much of your time to explain.
That must've taken at least an hour.

Now, the one question I have left pertains to the following (the tied
values (double mode)).

···

____________________________________

7stud -- wrote in post #1076263:
z = y.select {|a, b| b == y[0][1]}
p z

--output:--
[[30, 2]]

In this example, the conditional b == y[0][1] is equivalent to b == 2.
If instead you had results like this,

[[10, 3], [30, 3], [20, 1], [40, 1]]

...then the conditional would be b == 3, which just selects all the
numbers that tie for the most appearances in the original array.

____________________________________

How is "b == y[0][1]" similar to "b == 2" ?
Do you mean the value in the sorted hash?

When I call "top_count = nums_with_frequs[0][1]" am I referring to the
first key and value in the sorted hash "freq_for" (i.e. the var
"nums_with_frequs")?

I've played around with it but I don't see how to use "b == 3" to arrive
at the tied values.

--
Posted via http://www.ruby-forum.com/\.

Sung Pae wrote in post #1075726:

···

On Thu, Sep 13, 2012 at 12:46:23PM +0900, 7stud -- wrote:

Just forget inject() even exists. It's really quite a pathetic method.

inject is just reduce/foldl from other languages. It is just sugar for
building an accumulator in a foreach loop, but it has a long history.

It's also a baby step towards "functional programming" - realising that
you don't actually need mutable variables to do useful computation,
which in turn frees you from certain kinds of programming logic errors.

I really like how Ruby lets you do things like this on a small scale,
without having to go full-out functional.

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote in post #1075769:

However, with better variable names, it might be clearer what's going on
with inject:

class Array
  def sum1
    inject(0) {|total, array_element| total += array_element}
  end

The assignment is totally superfluous.

Whoops. Yep, otherwise it wouldn't be such a strange method.

  def sum2
    total = 0

    self.each do |array_element|
      total += array_element
    end

    total
  end

Here "self." is superfluous. :wink:

Yep. I write it anyway. In my opinion, it's 10 times clearer with an
explicit receiver.

···

On Thu, Sep 13, 2012 at 5:55 AM, 7stud -- <lists@ruby-forum.com> wrote:

--
Posted via http://www.ruby-forum.com/\.

incag neato wrote in post #1076331:

When I call "top_count = nums_with_frequs[0][1]" am I referring to the
first key and value in the sorted hash "freq_for" (i.e. the var
"nums_with_frequs")?

I've played around with it but I don't see how to use "b == 3" to arrive
at the tied values.

In my example:

nums_with_frequs = [[30,2]]

...which you could have easily determined yourself by printing it out.

···

--
Posted via http://www.ruby-forum.com/\.