0

I have a string:

key = "41521"

And I want to convert it into an array like this:

array = [41, 15, 52, 21]

I went about it like so:

array = []
array << key[0..1].to_i
array << key[1..2].to_i
array << key[2..3].to_i
array << key[3..4].to_i

What would be a better way?

1
  • There are two problems with your approach. The main one is that it only works when array contains 4 elements. In addition, your code contains excessive repetition. For example, you could write (0..key.size-2).each_with_object([]) { |i,array| array << key[i,2].to_i } #=> [41, 15, 52, 21]. Note that Enumerable#each_with_object merely serves to eliminate the need for array = [] at the beginning an array (to return the computed value of array) at the end. Commented Mar 18, 2018 at 4:46

4 Answers 4

6
key = "41521"

key.each_char.each_cons(2).map { |a| a.join.to_i }
  #=> [41, 15, 52, 21]

or

key.gsub(/\d(?=(\d))/).with_object([]) { |s,a| a << (s<<$1).to_i }
  #=> [41, 15, 52, 21]

or

a = []
e = key.each_char
  #=> #<Enumerator: "41521":each_char>
loop { a << (e.next << e.peek).to_i }
a #=> [41, 15, 52, 21]

In #3 Enumerator#peek raises a StopInteration exception when the internal position of the enumerator is at the end (unless key is an empty string, in which case Enumerator#next raises the StopInteration exception). Kernel#loop handles the exception by breaking out of the loop.

Sign up to request clarification or add additional context in comments.

5 Comments

Last one is nice. Also you could chain the loop with with_object.
I've noticed that you seem to have gained a fondness for enumerators.
I do enjoy your use of next and especially peek, it's very neat. I'll occasionally take a stab using said methods but I definitely wouldn't have thought to use them here.
How does the loop terminate exactly?
@Sagar, I added an answer to your question to my answer.
2
key.gsub(/(?<=.)\d(?=.)/, '\&\&').scan(/\d{2}/).map(&:to_i)
# => [41, 15, 52, 21]

or

(0...key.length).map{|i| key[i, 2].to_i}
# => [41, 15, 52, 21, 1]

3 Comments

Don't you want 0...key.length-1?
@CarySwoveland yes, though length-2 should be correct and I really like that solution
@vol7ron, note that sawa has used three dots for the range.
1

Not as short as some other answers, but for me, more easier to see the steps:

arr = key.chars.each_with_index
         .reduce([]) {|s,(v,i)| s << (v + (key[i+1] || '')).to_i }
         .select {|s| s.to_s.length > 1 }

# arr: [41, 15, 52, 21]

2 Comments

You can use chars instead of split(''). Or even each_chars.
Thanks Sagar (ruby is not my forte) :)
0
(0..(key.length-2)).map{|i| key.slice(i, 2)}

2 Comments

add a .to_i in there
Hieu, @Phlip meant that you need to write key.slice(i,2).to_i, as an array of integers is desired.

Your Answer

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