Getting an array of integers from console - ruby

I am trying to take in an array of integers from console user input. I thought that the function I need to use was gets, but now I am remembering that this function is going to take in a string, not an array. Can someone help me with how to convert this string into an array? Here is what I have tried to do so far:
print "Enter array: "
a = Array.new
a = gets.chomp
my_function(a)
Expected input: [1,2,3,4]

You could always eval it, but dangerous as heck...
>> foo = "[0,5,3,2,20,10]"
=> "[0,5,3,2,20,10]"
>> a = eval foo
=> [0, 5, 3, 2, 20, 10]
>> a
=> [0, 5, 3, 2, 20, 10]
>> a.class
=> Array
>>
could they could do something like this..
>> foo = "[0,5,3,2,20,10] - a"
=> "[0,5,3,2,20,10] - a"
>> a = eval foo
=> []
>>
or worse

Your input format seems to be JSON or YAML, so you could just parse it with a JSON parser or YAML parser:
require 'json'
a = JSON.parse(gets) # [1, 2, 3, 4]
# => [1, 2, 3, 4]

This is a contrived example that takes a user-inputted string of single-digit integers, creates an array via the String::split method, and converts each element from string to integer:
puts "Enter array: " # enter this string: 1234
str = gets.chomp
puts str.class #=> String
arr = str.split(//).map(&:to_i)
puts arr.class #=> Array
puts arr.size #=> 4
puts arr.inspect #=> [1, 2, 3, 4]
This is far from a full solution (i.e. assumes no delimiter in string, would only work for single-digit integers, etc.), but it demonstrates the basic concept.

print "Enter array: "
a = gets.chomp
a.gsub!(/\[|\]/, "").split(',').map(&:to_i)
my_function(a)
In your example you are doing a = ... twice. The first assignment of a is overwritten by the second assignment, so the first assignment is doing nothing. Just so you know.
What I am doing in the third line here is I am mutating the string "[1,2,3,4]" into an Array of integers.
Sources:
http://ruby-doc.org/core-2.2.0/String.html#method-i-split
http://ruby-doc.org/core-2.2.0/String.html#method-i-gsub-21
http://ruby-doc.org/core-2.2.0/Array.html#method-i-map

Related

Select specific character positions from string

I'm looking for a way to select pseudo random characters from a string.
For example, I have a 64 character string. I would like to pick positions 0, 1, 4, 5, 8, 9.
Or a harder one would be with the same string, I would pick positions 0, 1, 2, 4, 6, 8, 10, 11, 12 and so on.
Is there a quick way to do this?
Here's something that may work well for you:
#!/usr/bin/env ruby
# Returns a string whose length is a random number between 0
# and the string length, and whose values are characters from
# random positions in the input string.
def random_string_char_subset(string)
chars = string.chars.shuffle
char_count = Random.rand(string.length + 1)
subset = ''
char_count.times { subset << chars.pop }
subset
end
puts random_string_char_subset 'hello' # => lhl
puts random_string_char_subset '0123456789' # => 821097634
puts random_string_char_subset 'bye' # => b
Yes, you could use Array#values_at
> "64charstring".chars.values_at(*[0, 1, 4])
=> ["6", "4", "a"]
Update:
And if you'd like to get string result - join the result.
> "64charstring".chars.values_at(*[0, 1, 4]).join
=> "64a"
This can be done using []
a = 'test string'
a[1] #=>e, assuming you are using a known value
a[Random.rand(a.length)] #assuming you want a random value

Take all items with enumerable#take

How can I Enumerable#take all the things?
arr = [1, 2, 3]
# Works
arr.take(1)
# Gives RangeError: float Inf out of range of integer
arr.take(Float::INFINITY)
# Gives RangeError: float Inf out of range of integer
arr.take(1.0/0.0)
# RangeError: bignum too big to convert into `long'
arr.take(1000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000)
# TypeError: no implicit conversion from nil to integer
arr.take(nil)
If it's not possible to take all items with Enumerable#take, then I'd have to have the convoluted code in display_results_allowing_all_objects rather than the simple code in display_results.
MAX_ROWS = 1
# Simple code: Only two lines long.
def display_results(results)
results_to_display = results.take(MAX_ROWS)
puts results_to_display.map{|result| result.join("\t")}.join("\n")
end
results = [["Foo", 1], ["Bar", 2], ["Baz", 3]]
display_results(results)
NEW_MAX_ROWS = Float::INFINITY
# Convoluted mess: six lines long
def display_results_allowing_all_objects(results)
results_to_display = if NEW_MAX_ROWS == Float::INFINITY
results
else
results_to_display = results.take(NEW_MAX_ROWS)
end
puts results_to_display.map{|result| result.join("\t")}.join("\n")
end
display_results_allowing_all_objects(results)
You can use Enumerable#take_while to take all the items
$> arr.take_while { true }
# => [1, 2, 3]
We can do the [0..-1]. But with .. you can't get 0 items while with ... you can't get all of them. If you can deal with inability to get 0 results, use .., but you'll have to do -1, so the 0 will mean the all results:
results_to_display = results[0 .. rows_to_take-1]
You could cast #to_a which would take everything:
arr = [1, 2, 3]
arr.to_a
#=> [1, 2, 3]
(1..4).lazy.to_a
#=> [1, 2, 3, 4]

Iterator calls all elements at once within an each block

I build the array here:
def initialize
#names = []
end
#names << page.all('//*[#id="USERS_AVAIL"]/option').map {|result| result.text.split(", ")}
later on I'm trying to compile and visit url's by iterating through the names array like so:
#names.each do |name|
visit "https://example.com/k=#{name}&tpe=1"
end
Some puts statements show me that the each method is calling every element of the array all at once instead of iterating as intended. I.E.: "https://example.com/k=#{[[%22Adviento%22,%20%22Justin%22],%20[%22Asamoah%22,%20%22Nathan%22],%20[%22Baughman%22,%20%22Zachary%22],}&tpe=1". #names.length has a count of only 4 but a puts of the #names array shows the proper output? I'm not sure what could be wrong, thanks in advance for any assist.
Replace << with +=. The << is inserting the entire array as a single element of its own, whereas += will concatenate the array, which seems to be your intention.
For example:
a = [1,2,3]
# => [1, 2, 3]
a << [4,5,6]
# => [1, 2, 3, [4, 5, 6]] # WRONG
a = [1,2,3]
# => [1, 2, 3]
a += [4,5,6]
# => [1, 2, 3, 4, 5, 6] # CORRECT
Try:
#names += page.all('//*[#id="USERS_AVAIL"]/option')
.map { |r| r.text.split(',').map(&:strip) }.flatten
If the quotes are in the literal form %22 and you want to capture the strings in between them:
#names += page.all('//*[#id="USERS_AVAIL"]/option')
.map { |r| r.text.scan(/%22([^%]+)%22/) }.flatten

Ruby: Building a hash from a string and two array values at a time

I'm trying to build a hash with:
hash = {}
strings = ["one", "two", "three"]
array = [1, 2, 3, 4, 5, 6]
so that I end up with:
hash = { "one" => [1, 2] ,
"two" => [3, 4] ,
"three" => [5, 6] }
I have tried:
strings.each do |string|
array.each_slice(2) do |numbers|
hash[string] = [numbers[0], numbers[1]]
end
end
But that yields:
hash = { "one" => [5,6] , "two" => [5,6], "three" => [5,6] }
I know why it does this (nested loops) but I don't know how to achieve what I'm looking for.
If you want a one-liner:
hash = Hash[strings.zip(array.each_slice(2))]
For example:
>> strings = ["one", "two", "three"]
>> array = [1, 2, 3, 4, 5, 6]
>> hash = Hash[strings.zip(array.each_slice(2))]
=> {"one"=>[1, 2], "two"=>[3, 4], "three"=>[5, 6]}
hash = {}
strings.each { |string| hash[string] = array.slice!(0..1) }
This is a solution using methods and techniques you seem familiar with. It is not a 'one liner' solution but if you are new might be more understandable for you. The first answer is very elegant though.
As Mu says, Zip method is the best choose:
Converts any arguments to arrays, then merges elements of self with corresponding elements from each argument. This generates a sequence of self.size n-element arrays, where n is one more that the count of arguments. If the size of any argument is less than enumObj.size, nil values are supplied. If a block is given, it is invoked for each output array, otherwise an array of arrays is returned.

How to initialize an array in one step using Ruby?

I initialize an array this way:
array = Array.new
array << '1' << '2' << '3'
Is it possible to do that in one step? If so, how?
You can use an array literal:
array = [ '1', '2', '3' ]
You can also use a range:
array = ('1'..'3').to_a # parentheses are required
# or
array = *('1'..'3') # parentheses not required, but included for clarity
For arrays of whitespace-delimited strings, you can use Percent String syntax:
array = %w[ 1 2 3 ]
You can also pass a block to Array.new to determine what the value for each entry will be:
array = Array.new(3) { |i| (i+1).to_s }
Finally, although it doesn't produce the same array of three strings as the other answers above, note also that you can use enumerators in Ruby 1.8.7+ to create arrays; for example:
array = 1.step(17,3).to_a
#=> [1, 4, 7, 10, 13, 16]
Oneliner:
array = [] << 1 << 2 << 3 #this is for fixnums.
or
a = %w| 1 2 3 4 5 |
or
a = [*'1'..'3']
or
a = Array.new(3, '1')
or
a = Array[*'1'..'3']
Along with the above answers , you can do this too
=> [*'1'.."5"] #remember *
=> ["1", "2", "3", "4", "5"]
To prove There's More Than One Six Ways To Do It:
plus_1 = 1.method(:+)
Array.new(3, &plus_1) # => [1, 2, 3]
If 1.method(:+) wasn't possible, you could also do
plus_1 = Proc.new {|n| n + 1}
Array.new(3, &plus_1) # => [1, 2, 3]
Sure, it's overkill in this scenario, but if plus_1 was a really long expression, you might want to put it on a separate line from the array creation.
You can do
array = ['1', '2', '3']
As others have noted, you can also initialize an array with %w notation like so:
array = %w(1 2 3)
or
array = %w[1 2 3]
Please note that in both cases each element is a string, rather than an integer.
So if you want an array whose elements are integers, you should not wrap each element with apostrophes:
array_of_integers = [1, 2, 3]
Also, you don't need to put comma in between the elements (which is necessary when creating an array without this %w notation). If you do this (which I often did by mistake), as in:
wrong_array = %w(1, 2, 3)
its elements will be three strings ---- "1,", "2,", "3". So if you do:
puts wrong_array
the output will be:
1,
2,
3
=>nil
which is not what we want here.
Hope this helps to clarify the point!
To create such an array you could do:
array = ['1', '2', '3']
If you have an Array of strings, you can also initialize it like this:
array = %w{1 2 3}
just separate each element with any whitespace
You can initialize an array in one step by writing the elements in [] like this:
array = ['1', '2', '3']
You can simply do this with %w notation in ruby arrays.
array = %w(1 2 3)
It will add the array values 1,2,3 to the arrayand print out the output as ["1", "2", "3"]

Resources