unexpected tINTEGER, expecting $end - ruby

I'm learning ruby and can't figure out what's the problem here.
formatter = "%s %s %s %s"
puts formatter = % [1, 2, 3, 4]
Result:
ex8.rb:3: syntax error, unexpected tINTEGER, expecting $end
puts formatter = % [1, 2, 3, 4]
^

You either a) Don't need that = sign:
formatter = "%s %s %s %s"
puts formatter % [1, 2, 3, 4]
or b) need to assign the result to formatter differently:
formatter = "%s %s %s %s"
puts formatter = formatter % [1, 2, 3, 4]
or
formatter = "%s %s %s %s"
formatter = formatter % [1, 2, 3, 4]
puts formatter
The former answer for b will assign the result to formatter and then output the result of that assignment, which will be the right-hand side. I'd recommend the latter (and you could of course condense the top two lines into a single line) just because it's clearer.
Edit:
Also, if you check the code in Learn Ruby the Hard Way, they're not reassigning anything to formatter. The point is that you can supply any four-item array via formatter % and it will produce the text content of those four items. I see it's just dipping into Ruby methods (and you may be unfamiliar with printf), but the following are equivalent:
puts formatter % [1, 2, 3, 4]
puts formatter.%([1, 2, 3, 4])
# And the very retro
puts sprintf(formatter, 1, 2, 3, 4)
In other words, while there are a few nuances for operators -- just some sugar that you can actually use things like %= to assign the result and you don't need the . separating the object and its method -- these are just methods. You can look up % in Ruby's documentation like any other method.

It's not completely clear what is that you are trying to do. Maybe this?
formatter = "%s %s %s %s"
puts formatter % [1, 2, 3, 4]
# >> 1 2 3 4

Well these are called format specification with arguments,
"I got the following values: %s, %d, %d and %d" % ["Tom", 2, 3, 4]
=> "I got the following values: Tom, 2, 3 and 4"
"%05d" % 123
=> "00123"
More you can find at http://ruby-doc.org/core-1.9.3/String.html#method-i-25

Related

Return an array between start A and B

$array = []
def range(start_position,end_position)
for i in start_position..end_position
$array.push(i)
puts $array
end
return $array
end
range(1,10)
I was wondering why exactly my array isnt returning. Clearly when I do puts $array, 1-10 is being inserted, but when I call my function I want the array to be returned. Any thoughts, I'm reading through documentation but can't find what i've done wrong or if I have made any syntax errors.
It returns an array, but you are not doing anything with it, so it is discarded. You could print it (with p range(1,10) or puts range(1,10) ) or assign it to a variable for later use ( result = range(1,10) ). Which is the same as result = (1..10).to_a, not using your method at all.
Your code is essentially correct you just need to omit the puts $array within your for block. And also no need for the optional return keyword. So fixing your code we would have:
$array = []
def range(start_position,end_position)
for i in start_position..end_position
$array.push(i)
end
$array
end
p range(1,10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Kernel#p performs the Kernel#inspect method which as stated in the documentation provides a human-readable representation of the object in question. In Ruby it would be much better to do something like this perhaps:
def range(start_position,end_position)
(start_position..end_position).map {|i| i }
end
p range(1,10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Your array does return, but you don't do anything with the return value. Try saving it to a variable or print the result:
print range(1, 3) # => [1, 2, 3]
If you're looking for a simpler way to implement this function, you could use Ruby ranges to do it, something like:
def range (start_position, end_position)
# Create a range and convert it to an array
# We can omit return
(start_position .. end_position).to_a
end
print range(1, 3) # => [1, 2, 3]
Also beware your function will only work the first time, because you're using a global variable as your starting point. Check what happens when you call it multiple times:
print range(1, 3) # => [1, 2, 3]
print range(1, 3) # => [1, 2, 3, 1, 2, 3]

Getting an array of integers from console

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

How do I slice an array into arrays of different sizes and combine them?

I want something as simple as the pseudocode below:
ar = [4,5,6,7,8,9]
last = ar.length-1
s = ar[0, 1..3, last] #fake code
puts s
Expected output has no 8:
4,5,6,7,9
Error:
bs/test.rb:12:in `[]': wrong number of arguments (3 for 2) (ArgumentError)
I know that it can accept only two args. Is there a simple way to get what I need ?
You almost have it, you're just using the wrong method, you should be using Array#values_at instead of Array#[]:
ar.values_at(0, 1..3, -1)
# => [4, 5, 6, 7, 9]
Also note that in Ruby, indices "wrap around", so that -1 is always the last element, -2 is second-to-last and so on.
You can do it this way also -
ar = [4,5,6,7,8,9]
arr = []
arr << ar[0..0] #arr[0] will return a single value but ar[0..0] will return it in array.
arr << ar[1..3]
arr << ar[-1..-1]
on printing arr it will give following output -
[[4], [5, 6, 7], [9]]

% notation in Ruby

I've read % notation but I could not find the explanation about the followings.
Example 1: The following code with % outputs i. Obviously % changes i to a string. But I am not sure what actually % is doing.
irb(main):200:0> [[1,2,3],[4,5,6]].each{ |row| p row.map{ |i| % i } }
["i", "i", "i"]
["i", "i", "i"]
=> [[1, 2, 3], [4, 5, 6]]
irb(main):201:0> [[1,2,3],[4,5,6]].each{ |row| p row.map{ |i| i } }
[1, 2, 3]
[4, 5, 6]
=> [[1, 2, 3], [4, 5, 6]]
Example 2: It seems %2d adding 2 spaces in front of a number. Again, I am not sure what %2d is doing.
irb(main):194:0> [[1,2,3],[4,5,6],[7,8,9]].each{ |row| p row.map{|i| "%2d" % i } }
[" 1", " 2", " 3"]
[" 4", " 5", " 6"]
[" 7", " 8", " 9"]
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Where can I find the documentation about these?
Here is the doc - You may also create strings using %:.
There are two different types of % strings %q(...) behaves like a single-quote string (no interpolation or character escaping) while %Q behaves as a double-quote string.....
In your first example p row.map{|i| % i } as per the above doc % i creates a string "i".
Examples :-
[1, 2, 3].map { |i| % i } # => ["i", "i", "i"]
% i # => "i"
Just remember as doc is saying -
Any combination of adjacent single-quote, double-quote, percent strings will be concatenated as long as a percent-string is not last.
From the wikipedia link
Any single non-alpha-numeric character can be used as the delimiter, %[including these], %?or these?,...
Now in your case it is %<space>i<space>. Which in the link I mentioned just above are %[..], %?..? etc.. That is why %<space>i<space> gives "i". (I used <space> to show there is a space)
Read Kernel#format
Returns the string resulting from applying format_string to any additional arguments. Within the format string, any characters other than format sequences are copied to the result.
The syntax of a format sequence is follows.
%[flags][width][.precision]type
A format sequence consists of a percent sign, followed by optional flags, width, and precision indicators, then terminated with a field type character. The field type controls how the corresponding sprintf argument is to be interpreted, while the flags modify that interpretation.
Your last question actually points to a method str % arg → new_str.
If IRB made you fool, like made me while trying to understand % i, don't worry, have a look - why in IRB modulo string literal(%) is behaving differently ?. Good answer Matthew Kerwin is given there.

Taking the input as a comma separated list from a user

this is my code to return the elements that are present
exactly once in the array
a = [1,2,2,3,3,4,5]
p a.select{|i| a.count(i) == 1}
# >> [1, 4, 5]
can anyone please suggest how to take the array as keyboard input from user??
print "Enter an array: "
STDOUT.flush
arr = STDIN.gets.chomp.split(/,/).map(&:to_i)
# Enter an array: 1,2,2,3,3,4,5 <ENTER>
arr # => [1, 2, 2, 3, 3, 4, 5]
Here's a pretty concise way of collecting a set amount of input into an array:
n = 7
a = n.times.collect { gets.chomp.to_i }
Then you can use your existing code on a.
irb(main):022:0> a = n.times.collect{gets.chomp.to_i}
1
2
2
3
3
4
5
=> [1, 2, 2, 3, 3, 4, 5]
irb(main):023:0> a.select{|i| a.count(i) == 1}
=> [1, 4, 5]
Below way:
s=gets.chomp
a = s.split("")
Use the gets method to get a string from standard input. (It's short for "get string"!)
chomp removes trailing whitespace, i.e. the newline character that results from pressing enter at the end of your input.
So, calling str = gets.chomp and entering 1 2 2 3 3 4 5 at the prompt will set str to "1 2 2 3 3 4 5". Then, just use str.split to convert it to an array.

Resources