0

I'm trying to turn strings in my array

values = (1..10).to_a + ["Jack(11)", "Queen(12)", "King(13)", "Ace(14)"]

into an integer, then sort the array with

def straight(hand)
  numbers = hand.each { |card| card.to_i }
  numbers.sort
end

and I keep getting the error

["Jack(11)", 9, 10, "Queen(12)", "Ace(14)"]
5carddraw.rb:58:in `sort': comparison of String with 10 failed (ArgumentError)

can anyone tell me how I can make this work?

5
  • what should be the ideal value of vaules? Commented Mar 31, 2015 at 18:24
  • from your first line of code posted in your question, what do you want to achieve? Commented Mar 31, 2015 at 18:30
  • 1
    you should store the cards like Jack, Queen, King, Ace as integers and then convert them to names as need be e.g. FACE_CARDS = {11 => "Jack", 12 => "Queen", 13 => "King", 14 => "Ace"} then def name;FACE_CARDS[value] || value;end would work fine. e.g. 10 would return 10 where as 11 would return "Jack" Commented Mar 31, 2015 at 18:31
  • @shivam means that you should edit your question to add something like, "My desired result is to return the array, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]", assuming that's what you want. I agree. It's not too late to do that. Commented Mar 31, 2015 at 19:11
  • I would remove the links. They don't add anything and are a distraction. Also, a small point, instead of "turn strings in my array into an integer", you should say "turn strings in my array into integers" or, better, "turn each string in my array into an integer". Commented Mar 31, 2015 at 19:18

2 Answers 2

1

There are a couple misunderstandings here.

each

each iterates through an array, passing each element to a block, and then returns the array itself. So each does not make any changes to the array (unless you specifically tell it to). Since your block just calls to_i, the end result is numbers == hand:

ary = ["Jack(11)", "Queen(12)", "King(13)", "Ace(14)"]
tmp = ary.each { |card| card.to_i }
p tmp
# ["Jack(11)", "Queen(12)", "King(13)", "Ace(14)"]

So you end up sorting an array containing numbers and strings, which is what your error is complaining about. You want to use map, which returns a new array using the results of the block.

to_i

to_i does very simple conversion from string to integer: if the string starts with some digits (ignoring whitespace), it makes a number out of those digits. If the string doesn't start with digits, it returns 0:

" 1 2".to_i       # 1
"99bottles".to_i  # 99
"match3".to_i     # 0

Since your numbers are in the middle of the strings, you need something more advanced, like a regexp, to extract them:

"Jack(11)"[/\d+/].to_i # 11
Sign up to request clarification or add additional context in comments.

6 Comments

Awesome! thank you! Do you have any references for documentation on regexp that I can read?
I added a link to my answer. The official docs give a quick crash course on them but regexps are basically an entire language of their own.
Good answer. Putting it all together, values.map { |e| (e.is_a? String) ? e[/\d+/].to_i : e }.sort #=> [1,2,...,14].
Hackier, but shorter, e.to_s[/\d+/].to_i
I agree with the excellent use of regexp, but I still think the users problems are more based in their choice of data structure. If they aren't parsing someone else's data (which they might, maybe running through a bunch of hands that were recorded from earlier games that were scraped into a text file) then they should start with suitable data structure. If they are in fact writing some sort of card game, a regexp is just treating the symptom rather than the problem.
|
0

edit I've wrapped these long lines to make this post easy to read, must copy and paste into irb will suck. Sorry.

 values = ("1".."10").to_a + ["Jack(11)", "Queen(12)", "King(13)",  "Ace(14)"]

returns:

["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack(11)", 

"Queen(12)", "King(13)", "Ace(14)"]

But values.sort will give:

["1", "10", "2", "3", "4", "5", "6", "7", "8", "9", "Ace(14)",
 "Jack(11)", "King(13)", "Queen(12)"]

So you can do:

values = ("01".."10").to_a + ["Jack(11)", "Queen(12)", "King(13)", "Ace(14)"]

which will return:

["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", 

"Jack(11)", "Queen(12)", "King(13)", "Ace(14)"]

but still values.sort gives:

["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "Ace(14)",

"Jack(11)", "King(13)", "Queen(12)"]

So finally you could do:

values = ("01".."10").to_a + ["(11)Jack", "(12)Queen", "(13)King", "(14)Ace"]

wich gives:

["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", 

 "(11)Jack", "(12)Queen", "(13)King", "(14)Ace"]

so you try values.sort and get...

["(11)Jack", "(12)Queen", "(13)King", "(14)Ace", "01", "02", "03", 

"04", "05", "06", "07", "08", "09", "10"]

Darn it! Still not working. What does all this tell you? The array you are trying to use is the wrong data structure. Use a Hash and stop trying to sort anything:

values = {one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7,

 eight: 8, nine: 9, ten: 10, jack: 11, queen: 12, king: 13, ace: 14}

def straight(hand)
  numbers = hand.values.sort
end 

straight(values)

  #returns => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Look at all of the methods in the Hash and Enumerable classes. These will give you a huge arsenal of dealing with your hash of card values. Many of these methods will do something that you have already, or probably will do with a larger chunk of code.

As I think about this, I would create a Hash as my dictionary, using strings instead of the written number as I show above:

Values = {"1" => 1, "2" => 2, "3" => 3, "4" => 4, "5" => 5, "6" => 6,
 "7" => 7, "8" => 8, "9" => 9, "10" => 10, "Jack" => 11, "Queen" => 12,
 "King" => 13, "Ace" => 14} 

#note we are using a Constant now with "Values". We want to access this anywhere and for it to not change.

Then you can use the strings where you are displaying cards, but when you want to lookup a hand's value you can convert it to a numeric array:

hand = ["2", "4", "10", "Ace", "King"]
def hand_value(hand)
  hand.map { |card| Values[card]}
end
    # => [2, 4, 10, 14, 13]

now you can manipulate the value of the hand any way you want. You can check to see if they are consecutive, sum them up, etc.

To look up a value:

Values["King"] #=> 13

to do the reverse and look up a key:

Values.key(13) #=> "King"

2 Comments

I like your answer format here, but I'd like it better if you formatted so that the reader doesn't have to scroll horizontally. Aside: why do I want to call you 'Beartooth'?
I hate having to scroll too. What is the preferred method to post code that wraps but can still be copied and pasted? I'll admit Beartooth is probably a cooler name, LOL! Maybe I should switch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.