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
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
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
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"]
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}
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)