Inject problem

Hello,

I have a array like this [ 1.2.1.1]
Now I want a hash which contains the numbers and the count.
So I thought this would work : count.inject { |1, array.count(1)| }

But I get a lot of syntax errors.

Can anyone give me a hint where I am going wrong ?

Roelof

On Tue, Sep 25, 2012 at 10:41 AM, Roelof W. [email protected]
wrote:

Hello,

I have a array like this [ 1.2.1.1]

Well, first of all this is not correct. It should be:

count = [1,2,1,1]

Now I want a hash which contains the numbers and the count.
So I thought this would work : count.inject { |1, array.count(1)| }

This doesn’t even make sense to me.

But I get a lot of syntax errors.

Can anyone give me a hint where I am going wrong ?

If you want to do that you need to create a Hash. Then iterate through
the array adding 1 to the value in the hash for each element of the
array.

Jesus.

Well the simplest error is the count.inject{| … |} part. The stuff
that goes between the | … | are variable declarations. For example
this is sum for an array

array = [1,2,1,1]
array.inject(0){|x, y| x + y} => 5

note the variable ‘x’ and ‘y’ are between the | … | and the action
‘x + y’ takes place after. inject is expecting two variable to be
declared so that is another error.

Hi,

Using “inject” really isn’t a good choice here. If at all, I’d use
“each_with_object” to build up the hash.

If you don’t need the whole hash at once, you could also use the block
form of Hash.new to calculate the elements on demand:

arr = [1, 2, 1, 1]

count_hash = Hash.new do |hash, key|
cnt = arr.count key
cnt == 0 ? nil : hash[key] = cnt
end

p count_hash[1]

Or you could do something like this:

arr = [1, 2, 1, 1]

arr_uniq = arr.uniq
count_hash = Hash[arr_uniq.zip arr_uniq.map {|e| arr.count e}]

p count_hash

try this,
count.inject({}){|x,y| x[y] += 1 rescue x[y] = 1; x}

On Tue, Sep 25, 2012 at 2:25 PM, Peter H. <

On Tue, Sep 25, 2012 at 11:31 AM, Jan E. [email protected] wrote:

Hi,

Using “inject” really isn’t a good choice here. If at all, I’d use
“each_with_object” to build up the hash.

My preferred solution:

count = [1,2,1,1]
h = Hash.new(0)
count.each {|el| h[el] += 1}
p h #=> {1=>3, 2=>1}

Jesus.

All thanks for the explanation.

I have one question about the solution of Prasadhnc C

When I do this :

array.each do |x|
count.inject({}){|x,y| x[y] += 1 rescue x[y] = 1; x}
end

where x = array [ 1, 2 , 1 , 1]

Then I don’t get the counted answers.

Roelof

just do:

array = [ 1, 2 , 1 , 1]

p array.inject({}){|x,y| x[y] += 1 rescue x[y] = 1; x}

Roelof W. wrote in post #1077457:

I have one question about the solution of Prasadhnc C

Haven’t you read the other postings? :frowning:

“inject” is completely useless in your case, since you don’t do what
it’s meant for: building a value by subsequently calling the block. You
just pass the same object again and again. Yes, “inject” still works.
But you basically circumvent the actual mechanism – in which case
“each_with_object” would be a better fit.

Or do you want to use “inject” no matter what?

Hello, Of course I have read all the other postings.I only try to
understand how all the solutions work and I understand that inject is
not a good solutionand I better can use each_with_object. Roelof

Date: Tue, 25 Sep 2012 22:14:43 +0900

The first parameter of the “inject” block is always the intermediate
result used for the aggregation. And the second is the current element.

For example:

calculate sum of 1, 2, …, 10 (in an inefficient way)

sum = (1…10).inject do |intermediate_sum, integer|
intermediate_sum + integer
end

Or in your case:

count = [1, 2, 1, 1]
hash = count.inject({}) do |intermediate_hash, number|
intermediate_hash[number] += 1 rescue intermediate_hash[number] = 1
intermediate_hash
end
puts hash

Hello,

One question so I can understand this way well.

In this context x = 1 or 2 and y is the place in the hash ?

Roelof

Hello,

I thought I solved this problem with this code :

def score(dice)
total = 0
h = Hash.new(0)
dice.each {|el| dice[el] += 1}

dice.each {|number, count|
if number == 1 and count == 3 then total = total + 1000 end
if number == 1 and count == 6 then return 2000 end
if number != 1 and count == 3 then total = total + 100 * count end
if number != 1 and count == 6 then return 600 end
if number == 1 and (count > 3) then total = total + ( 100 + ( count -
3)) end
if number == 1 and (count < 3) then total = total + 100 * count end
if number == 5 and (count > 3) then total = total + ( 50 * (count
-3)) end
if number == 5 and (count < 3) then total = total + 50 * count end
}
return total
end

But now I’m getting this error : undefined method `+’ for nil:NilClass

Roelof

On Tue, Sep 25, 2012 at 1:57 PM, Roelof W. [email protected]
wrote:

But now I’m getting this error : undefined method `+’ for nil:NilClass

On what line? Presumably the one that says:

dice.each {|el| dice[el] += 1}

This would imply that dice[el] is nil. Not surprising, since |el| is
the element, not the index. Maybe you meant something like:

dice.map! { |el| el + 1 }

or

dice.each_index { |idx| dice[idx] += 1 }

?

-Dave

On 9/25/12 4:18 PM, Roelof W. wrote:

Hello,

One question so I can understand this way well.

In this context x = 1 or 2 and y is the place in the hash ?

irb> array.inject({}){|x,y| puts “x:#{x}, y:#{y}”; x[y] += 1 rescue x[y]
= 1; x}
x:{}, y:1
x:{1=>1}, y:2
x:{1=>1, 2=>1}, y:1
x:{1=>2, 2=>1}, y:1
=> {1=>3, 2=>1}

thanks,

The only problem I have to solve is when dice is a empty array.
you now get [] as answer but the answer has to be 0.

Roelof

Roelof W. wrote in post #1077503:

h = Hash.new(0)
dice.each {|el| dice[el] += 1}
[…]
But now I’m getting this error : undefined method `+’ for nil:NilClass

You want h[el] += 1, not dice[el] += 1. See the original code by Jesús.

Thanks but I did not solve my problem.

Here is the whole script :

require File.expand_path(File.dirname(FILE) + ‘/edgecase’)

Greed is a dice game where you roll up to five dice to accumulate

points. The following “score” function will be used to calculate the

score of a single roll of the dice.

A greed roll is scored as follows:

* A set of three ones is 1000 points

* A set of three numbers (other than ones) is worth 100 times the

number. (e.g. three fives is 500 points).

* A one (that is not part of a set of three) is worth 100 points.

* A five (that is not part of a set of three) is worth 50 points.

* Everything else is worth 0 points.

Examples:

score([1,1,1,5,1]) => 1150 points

score([2,3,4,6,2]) => 0 points

score([3,4,5,3,3]) => 350 points

score([1,5,1,2,4]) => 250 points

More scoring examples are given in the tests below:

Your goal is to write the score method.

def score(dice)
total = 0
h = Hash.new(0)
dice.each {|el| h[el] += 1}

dice.each {|number, count|
if number == 1 and count == 6 then return 2000 end
if number != 1 and count == 3 then total = total + 100 * count end
if number != 1 and count == 6 then return 600 end
if number == 1 and (count > 3) then total = total + ( 100 + ( count -
3)) end
if number == 1 and (count < 3) then total = total + 100 * count end
if number == 5 and (count > 3) then total = total + ( 50 * (count
-3)) end
if number == 5 and (count < 3) then total = total + 50 * count end
}

end

class AboutScoringProject < EdgeCase::Koan
def test_score_of_an_empty_list_is_zero
assert_equal 0, score([])
end

def test_score_of_a_single_roll_of_5_is_50
assert_equal 50, score([5])
end

def test_score_of_a_single_roll_of_1_is_100
assert_equal 100, score([1])
end

def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores
assert_equal 300, score([1,5,5,1])
end

def test_score_of_single_2s_3s_4s_and_6s_are_zero
assert_equal 0, score([2,3,4,6])
end

def test_score_of_a_triple_1_is_1000
assert_equal 1000, score([1,1,1])
end

def test_score_of_other_triples_is_100x
assert_equal 200, score([2,2,2])
assert_equal 300, score([3,3,3])
assert_equal 400, score([4,4,4])
assert_equal 500, score([5,5,5])
assert_equal 600, score([6,6,6])
end

def test_score_of_mixed_is_sum
assert_equal 250, score([2,5,2,2,3])
assert_equal 550, score([5,5,5,5])
end

end

And I now get this error: <0> expected but was <[]>.
When I make that one a comment :

def test_score_of_an_empty_list_is_zero

#assert_equal 0, score([])

end

Then I see this error appear :

The answers you seek…
undefined method `>’ for nil:NilClass

Please meditate on the following code:
./about_scoring_project.rb:43:in score' ./about_scoring_project.rb:37:ineach’
./about_scoring_project.rb:37:in score' ./about_scoring_project.rb:56:intest_score_of_a_single_roll_of_5_is_50’
/home/roelof/koans/edgecase.rb:398:in send' /home/roelof/koans/edgecase.rb:398:inmeditate’
/home/roelof/koans/edgecase.rb:470:in walk' /home/roelof/koans/edgecase.rb:481:ineach_step’
/home/roelof/koans/edgecase.rb:479:in each' /home/roelof/koans/edgecase.rb:479:ineach_step’
path_to_enlightenment.rb:38:in each_with_index' /home/roelof/koans/edgecase.rb:478:ineach’
/home/roelof/koans/edgecase.rb:478:in each_with_index' /home/roelof/koans/edgecase.rb:478:ineach_step’
/home/roelof/koans/edgecase.rb:476:in catch' /home/roelof/koans/edgecase.rb:476:ineach_step’
/home/roelof/koans/edgecase.rb:469:in `walk’
/home/roelof/koans/edgecase.rb:491
path_to_enlightenment.rb:38

So something is not well here ?

Roelof

Roelof W. wrote in post #1077510:

The only problem I have to solve is when dice is a empty array.
you now get [] as answer but the answer has to be 0.

Yeah, you seem to have forgot “return total” at the end of the method
(you can leave out the “return”, of course). Otherwise the return value
is the result of “each” (which is an array).

You’re iterating over the wrong object. After you’ve build the hash, you
have to iterate over this hash and not the dices arrays again.

The dices array contains only the numbers. The h hash contains the
numbers and corresponding counts.

So it’s not

dice.each {|number, count| …

but

h.each {|number, count| …

Since there have been quite some errors now, you should be more careful
with the code you write. And you should get used to testing and
debugging code yourself. The error message is telling you that the “>”
operator has been applied to nil (namely the “count” variable). So if
you didn’t already know the problem, the first step would be to check
why “count” is nil. You’d do this by outputting “dice”, since that’s
what you’re iterating over. And then you’d probably realized that it’s
the completely wrong object.