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?
on 2012-09-13 04:09
on 2012-09-13 04:30
`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:
>
> 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
on 2012-09-13 05:46
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.
on 2012-09-13 05:50
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.
on 2012-09-13 05:55
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
def multiply_em
inject(1) {|total, array_element| total *= array_element}
end
end
puts [1, 2, 3].sum1
puts [1, 2, 3].sum2
puts [1, 2, 3].multiply_em
--output:--
6
6
6
on 2012-09-13 06:04
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
on 2012-09-13 06:13
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.
on 2012-09-13 09:42
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.
on 2012-09-13 12:46
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 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
on 2012-09-13 12:55
On Thu, Sep 13, 2012 at 5:55 AM, 7stud -- <lists@ruby-forum.com> wrote: > 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. ;-) Kind regards robert
on 2012-09-14 06:02
Robert Klemme wrote in post #1075769: > On Thu, Sep 13, 2012 at 5:55 AM, 7stud -- <lists@ruby-forum.com> wrote: >> 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. ;-) > I write it anyway. In my opinion, it's 10 times clearer with an explicit receiver.
on 2012-09-17 03:06
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!
on 2012-09-17 06:03
> 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}
x = result.sort_by {|key, val| val}
p x
--output:--
[[10, 1], [20, 1], [40, 1], [30, 2]]
y = result.sort_by {|key, val| -val}
p y
--output:--
[[30, 2], [10, 1], [20, 1], [40, 1]]
on 2012-09-17 06:25
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]
Finally, map selects the first element of all the sub arrays, where the
first element is a number that appeared the most times in the original
array.
on 2012-09-17 06:52
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]
Which do you prefer? Saving a few lines of code, or writing clear code?
on 2012-09-17 19:29
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.
on 2012-09-17 22:34
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.
on 2012-09-18 05:55
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]
on 2012-09-18 07:06
> 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.
on 2012-09-18 07:13
> >(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?
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.