Array elements to integers - ruby

I have an array of strings containing numbers:
array = ["1", "2", "3"]
I want to convert every string in the array to an integer.
array.each { |n| n.to_i } does not work, because
p array.inject(:+)
returns "123" (string) rather than 6 (integer)

array = ["1", "2", "3"]
new_array = array.map { |n| n.to_i }
p new_array.inject(:+)
=> 6

one-line solution:
array.map(&:to_i).inject(:+)
# => 6

Related

check if the index of similar elements in two arrays are different

This is my first question on StackOverFlow! Please let me know if my question is not clear.
Here is what I have so far:
code = ["4", "4", "1", "1"]
guess = ["4", "4", "4", "1"]
#A = 0
#B = 0
code.each_with_index do |item, index|
if item == guess[index]
#A += 1
elsif code.include?(guess[index])
#B += 1
end
print "\nA:#{#A} B:#{#B}"
end
I would like to increase #A by 1 if a number is in both arrays and in the same position (index).
If the number is in both arrays but in different positions (index), increase #B by 1.
I should've gotten A:3 B:0 but I am getting A:3 B:1. In the code array, there is no third "4" so B shouldn't have increased by 1.
Is it because .include? doesn't work with duplicates in arrays? How can I fix this?
After each successful (individual) match between the code and guess, we must remove the matched elements from the equation.
For example, code = ['1', 2'] and guess = ['1', '1']. We get an exact match at index 0. If we remove the matched elements: code = ['2'] and guess = ['1'], we can clearly see that there is no further match.
If we had not removed the elements, then (in addition to the exact match) index 0 of code would match with index 1 of guess... which would wrongly result in #A = 1 and #B = 1. We do not want to use an already matched code element to match with a different guess element.
code = ["4", "4", "1", "1"]
guess = ["4", "4", "4", "1"]
unmatched_code = []
unmatched_guess = []
#A = 0
#B = 0
code.size.times do |i|
if code[i] == guess[i]
#A += 1
else
unmatched_code << code[i]
unmatched_guess << guess[i]
end
end
unmatched_guess.each do |g|
matched_at_index = unmatched_code.index(g)
if matched_at_index
#B += 1
unmatched_code.delete_at(matched_at_index)
end
end
This should work:
code = ["4", "4", "1", "1"]
guess = ["4", "4", "4", "1"]
visited = Array.new(guess.length) { false }
#A = 0
#B = 0
code.each_with_index do |item, index|
if item == guess[index]
#A += 1
#B -= 1 if visited[index]
visited[index] = true
elsif guess.each_index.any? { |idx| guess[idx] == item && !visited[idx] && visited[idx] = true }
#B += 1
end
end
print "\nA:#{#A} B:#{#B}"
Here, I am keeping track of already visited indexes in the guess array so that I don't count the same element in both #A and #B count.
You could start by combining code and guess pairs via zip:
code = ["4", "3", "1", "1"]
guess = ["2", "3", "1", "4"]
pairs = code.zip(guess)
#=> [["4", "2"], ["3", "3"], ["1", "1"], ["1", "4"]]
To separate the exact matches, you could use partition:
exact_matches, remaining = pairs.partition { |a, b| a == b }
exact_matches
#=> [["3", "3"], ["1", "1"]]
remaining
#=> [["4", "2"], ["1", "4"]]
Your A-value is the number of exact matches:
a = exact_matches.size
#=> 2
And if remaining is empty?, you're already done here. But it is not:
remaining.empty?
#=> false
We therefore have to determine the number of partial matches. To do so, I would start by converting the remaining pairs back into their respective arrays via transpose:
code_remaining, guess_remaining = remaining.transpose
code_remaining
#=> ["4", "1"]
guess_remaining
#=> ["2", "4"]
Based on that arrays, you could calculate the number of their entries via tally:
code_hash = code_remaining.tally
#=> {"4"=>1, "1"=>1}
guess_hash = guess_remaining.tally
#=> {"2"=>1, "4"=>1}
There's 1 "4" and 1 "2" in the guess_hash. For each of these, we can check how many are actually available in the code_hash:
code_hash["4"] #=> 1
code_hash["2"] #=> nil
Because nil means 0 here, I would use fetch instead, which allows a default value to be passed:
code_hash.fetch("4", 0) #=> 1
code_hash.fetch("2", 0) #=> 0
And because there could be more available than guessed (or vice-versa), the actual value would be the minimum of them:
[guess_hash["4"], code_hash.fetch("4", 0)].min #=> 1
[guess_hash["2"], code_hash.fetch("2", 0)].min #=> 0
To get the B-value out of this, we have to sum the above:
b = guess_hash.sum { |k, v| [v, code_hash.fetch(k, 0)].min }
#=> 1

How to split a long number into pairs of digits

I have a string of a long number 12345678 and want to convert it to an array like this :
["12", "34", "56", "78"].
I have tried array.split(//).map { |e| e.to_i } but it does
["1", "2", "3", "4", "5", "6", "7", "8"]
The simplest way would be to use String#scan with the Regexp /../, which matches any pair of characters:
n = 12345678
arr = n.to_s.scan(/../)
# => ["12", "34", "56", "78"]
If you need to handle odd numbers of digits and keep the last digit, use /..?/ instead:
n = 123456789
arr = n.to_s.scan(/..?/)
# => ["12", "34", "56", "78", "9"]
An alternative approach would be to map over the range 0...n.to_s.size using the Range#step method:
n = 123456789
str = n.to_s
arr = (0...str.size).step(2).map {|i| str[i, 2] }
# => ["12", "34", "56", "78", "9"]
You can see all three approaches in action on repl.it: https://repl.it/#jrunning/BlissfulAcclaimedStrategy
I think there is no need to use a regexp, I would do something like this:
12345678.to_s.chars.each_slice(2).map(&:join)
#=> ["12","34","56","78"]
You can use
p = 123456789.to_s
(0..p.length).each_cons(2).map {|i, j| "#{p[i]}#{p[j]}" if i%2 == 0}.compact

Sort array of numbers in Scientific Notation

I would like to sort an array of numbers (in scientific notation) from the smallest to the highest.
This is what I have tried (in vain):
require 'bigdecimal'
s = ['1.8e-101','1.3e-116', '0', '1.5e-5']
s.sort { |n| BigDecimal.new(n) }.reverse
# Results Obtained
# => [ "1.3e-116", "1.8e-101", "0", "1.5e-5" ]
# Expected Results
# => [ "0", "1.3e-116", "1.8e-101", "1.5e-5"]
The block of Enumerable#sort is expected to return -1, 0 or 1. What you want is Enumerable#sort_by:
s.sort_by { |n| BigDecimal.new(n) }
# => ["0", "1.3e-116", "1.8e-101", "1.5e-5"]
Another option is to use BigDecimal#<=> within sort:
s.sort { |x, y| BigDecimal(x) <=> BigDecimal(y) }
#=> ["0", "1.3e-116", "1.8e-101", "1.5e-5"]

Converting an array into a hash with format { value => position_in_array }

I have an array of numbers in string format, and I want to convert them into a hash where the keys are the numbers and the values are the positions of those numbers in the array. So for example:
["1", "5", "3"]
should result in:
{ 1 => 0, 5 => 1, 3 => 2 }
I have the following code, which works:
my_hash = {}
my_array.each do |number_string|
my_hash[number_string.to_i] = my_array.index(number_string)
end
which iterates through the array and pushes each value and its position into the hash.
Is there a shorter and more elegant way to do it? Maybe something similar to Ruby's to_a function, but more like to_h(options).
Hash[["1", "5", "3"]
.map.with_index{|e, i| [e.to_i, i]}]
# => {1=>0, 5=>1, 3=>2}
or
["1", "5", "3"]
.each_with_object({}).with_index{|(e, h), i| h[e.to_i] = i}
# => {1=>0, 5=>1, 3=>2}
arr = ["1", "5", "3"]
ha = Hash[arr.map.with_index {|a, i| [a.to_i, i]}]
puts "ha: #{ha.inspect}"
irb(main):038:0> arr=["1", "5", "3"]
=> ["1", "5", "3"]
irb(main):039:0> Hash[arr.map.with_index {|a, i| [a, i]}]
=> {"1"=>0, "5"=>1, "3"=>2}
irb(main):040:0> Hash[arr.map.with_index {|a, i| [a.to_i, i]}]
=> {1=>0, 5=>1, 3=>2}

Simple ruby array smallest integer?

This is my array : array = ["1", "Hel", "6", "3", "lo" ]I want to output the smallest number in the array. Then I want to output the largest number in the array? How do I achieve this? Thanks!
Well it depends how you want to handle the string elements that aren't easily parsed into numbers. Like "Hel" and "lo".
If you do this:
array.map {|x| Integer(x) rescue nil }.compact.min
array.map {|x| Integer(x) rescue nil }.compact.max
Then you'll ignore those, which is probably the right thing, assuming you don't have some reason for considering "Hel" and "lo" to have numerical values.
numbers = array.select { |x| x[/^-?\d+$/] }.map(&:to_i)
# => [1, 6, 3]
numbers.min
# => 1
numbers.max
# => 6
Another variation to work with negative numbers
smalles, largest =
["1", "Hel", "6", "3", "lo","-9" ].select { |x| x[/^-?\d+$/] }.minmax_by(&:to_i)
smallest # => -9 largest # => 6
smallest, largest =
["1", "Hel", "6", "3", "lo" ].reject{|s| s =~ /\D/}.minmax_by(&:to_i)
smallest # => "1"
largest # => "6"
Another way:
array.join(',').scan(/-?\d+/).minmax_by(&:to_i)
#=> ["-4", "6"]
we can use unicode [[:digit:]] instead writing regular expression as
array.join(',').scan(/[[:digit:]]/).minmax_by(&:to_i)

Resources