how to get last few numbers of an element in an array? - ruby

array = [13845, 23424, 89021, 83628]
How would I return the last 2 numbers of each element?
expected output:
45
24
21
28
I have tried array[i].to_s.last(2) but I received the error message: "undefined method `last' for "13845":String"

Just use array.map in Ruby. String::last isn't standard Ruby and part of Rails ActiveSupport.
array.map { |e| e % 100 }

array.map { |i| i.to_s[-2..-1] } will do it in non-Rails Ruby, but CherryDT's handling of the elements as numbers is cleaner.
EDIT: It looks like CherryDT's answer has been removed, but
Armin Primadi does the same thing, and that is the better answer. I only offer this because of your attempt to use .to_s.

Related

How Type casting works in ruby on rails?

I am new to ruby on rails, I am trying to make operations in the class Activity < ActiveRecord::Base.
I am stuck at point where I need to convert an array of strings to integers.
The code is as below
#code from line 151
start_time_parts=start_time.split(":").collect{ |y| y.to_i }
start_time=Time.utc(2015,"jan",1,start_time_parts[0],start_time_parts[1],start_time_parts[2])
end_time_parts=end_time.split(":").collect{ |y| y.to_i }
end_time=Time.utc(2015,"jan",1,end_time_parts[0],end_time_parts[1],end_time_parts[2])
sql1='SELECT `Start_Time` FROM Times'
sql2='SELECT Rates FROM New_billcodes_mock WHERE Category_name=?, Instrument_name=? and Time_zone_name=?'
database_string_start_time =Activity.find_by_sql([sql1,'1'])
#error is here
string_start_time_parts=database_string_start_time.split(":").collect{ |y| Activity.type_cast(y)}
database_start_time=Time.utc(2015,"jan",1,string_start_time_parts[0],string_start_time_parts[1],string_start_time_parts[2])
I get the error message as
NoMethodError (undefined method `type_cast' for #<Class:0x4c25340>):
Apparently I cannot use to_i method as it is not a method of the class Activity. Please help me if there is an existing method that I can use to convert to integers.
There are many problems with this code, but to your specific question: in two places you use the { |y| y.to_i } construct to return integers; why are you not using that in the third instance ( { |y| Activity.type_cast(y)} ) as well? It's the same use case.
Or it would be if Activity.find_by_sql() didn't return an array, which makes splitting it on ':' pretty pointless - but that's a different question.
I think I got the solution to my problem. I used the global method Integer() to convert the string to integer.
{|y| y.to_i}
doesn't work because to_i is not a method in the class Activity

Ruby - Converting Strings to CamelCase

I'm working on an exercise from Codewars. The exercise is to convert a string into camel case. For example, if I had
the-stealth-warrior
I need to convert it to
theStealthWarrior
Here is my code
def to_camel_case(str)
words = str.split('-')
a = words.first
b = words[1..words.length - 1].map{|x|x.capitalize}
new_array = []
new_array << a << b
return new_array.flatten.join('')
end
I just tested it out in IRB and it works, but in codewars, it won't let me pass. I get this error message.
NoMethodError: undefined method 'map' for nil:NilClass
I don't understand this, my method was definitely right.
You need to think about edge cases. In particular in this situation if the input was an empty string, then words would be [], and so words[1..words.length - 1] would be nil.
Codewars is probably testing your code with a range of inputs, including the emplty string (and likely other odd cases).
The following works in Ruby 2 for me, even if there's only one word in the input string:
def to_camel_case(str)
str.split('-').map.with_index{|x,i| i > 0 ? x.capitalize : x}.join
end
to_camel_case("the-stealth-warrior") # => "theStealthWarrior"
to_camel_case("warrior") # => "warrior"
I know .with_index exists in 1.9.3, but I can't promise it will work with earlier versions of Ruby.
A simpler way to change the text is :
irb(main):022:0> 'the-stealth-warrior'.gsub('-', '_').camelize
=> "TheStealthWarrior"
This should do the trick:
str.gsub("_","-").split('-').map.with_index{|x,i| i > 0 ? x.capitalize : x}.join
It accounts for words with underscores
Maybe there's a test case with only one word?
In that case, you'd be trying to do a map on words[1..0], which is nil.
Add logic to handle that case and you should be fine.

Ruby: How to loop through an object that may or may not be an array?

I have an each method that is run on some user-submitted data.
Sometimes it will be an array, other times it won't be.
Example submission:
<numbers>
<number>12345</number>
</numbers>
Another example:
<numbers>
<number>12345</number>
<number>09876</number>
</numbers>
I have been trying to do an each do on that, but when there is only one number I get a TypeError (Symbol as array index) error.
I recently asked a question that was tangentally similar. You can easily force any Ruby object into an array using Array.
p Array([1,2,3]) #-> [1,2,3]
p Array(123) #-> [123]
Of course, arrays respond to each. So if you force everying into an array, your problem should be solved.
A simple workaround is to just check if your object responds to :each; and if not, wrap it in an array.
irb(main):002:0> def foo x
irb(main):003:1> if x.respond_to? :each then x else [x] end
irb(main):005:1> end
=> nil
irb(main):007:0> (foo [1,2,3]).each { |x| puts x }
1
2
3
=> [1, 2, 3]
irb(main):008:0> (foo 5).each { |x| puts x }
5
=> [5]
It looks like the problem you want to solve is not the problem you are having.
TypeError (Symbol as array index)
That error tells me that you have an array, but are treating it like a hash and passing in a symbol key when it expects an integer index.
Also, most XML parsers provide child nodes as array, even if there is only one. So this shouldn't be necesary.
In the case of arguments to a method, you can test the object type. This allows you to pass in a single object or an array, and converts to an array only if its not one so you can treat it identically form that point on.
def foo(obj)
obj = [obj] unless obj.is_a?(Array)
do_something_with(obj)
end
Or something a bit cleaner but more cryptic
def foo(obj)
obj = [*obj]
do_something_with(obj)
end
This takes advantage of the splat operator to splat out an array if it is one. So it splats it out (or doesn't change it) and you can then wrap it an array and your good to go.
I was in the same position recently except the object I was working with was either a hash or an array of hashes. If you are using Rails, you can use Array.wrap because Array(hash) converts hashes to an array.
Array({foo: "bar"}) #=> [[:foo, "bar"]]
Array.wrap({foo: "bar"}) #=> [{:foo=>"bar"}]
Array.wrap(123) #=> [123]
Array.wrap([123]) #=> [123]
I sometimes use this cheap little trick:
[might_be_an_array].flatten.each { |x| .... }
Use the splat operator:
[*1] # => [1]
[*[1,2]] # => [1,2]
Like Mark said, you're looking for "respond_to?" Another option would be to use the conditional operator like this:
foo.respond_to? :each ? foo.each{|x| dostuff(x)} : dostuff(foo);
What are you trying to do with each number?
You should try to avoid using respond_to? message as it is not a very object oriented aproach.
Check if is it possible to find in the xml generator code where it is assigning an integer value when there is just one <"number"> tag and modify it to return an array.
Maybe it is a complex task, but I would try to do this in order to get a better OO design.
I don't know much anything about ruby, but I'd assume you could cast (explicitly) the input to an array - especially given that if the input is simply one element longer it's automatically converted to an array.
Have you tried casting it?
If your input is x, use x.to_a to convert your input into an array.
[1,2,3].to_a
=> [1, 2, 3]
1.to_a
=> [1]
"sample string".to_a
=> ["sample string"]
Edit: Newer versions of Ruby seem to not define a default .to_a for some standard objects anymore. You can always use the "explicit cast" syntax Array(x) to achieve the same effect.

Sorting a Ruby array

I am trying to sort large inputs in the fastest way in ascending order. The code is something like this:
t=gets
ti=t.to_i
r=[]
for i in(0..ti)
k=gets
r[i]=k.to_i
end
r.sort_by{|x| -x.last}
This is giving me an error saying undefined method 'last' for nil:nilclass <nomethoderror>
from tsort.rb: in sort_by
from tsort.rb in 'each'
from tsort.rb in 'sort_by'
I don't know where am I wrong.
That's what I have tried for sorting an array...which is r[] which has all the numbers in t! Can anyone please help.
My inputs are less than 10^6!
I can't reproduce your exact error, I get undefined method 'last' for n:Fixnum (NoMethodError). That makes sense, because you're calling the last method on x, which will hold the values of your Array r, all Fixnums, which do not have a last method.
It should work if you replace the last line with:
r.sort
The sort method will sort your Array in ascending order by default.
If you want to sort a list of integers taken from STDIN I suggest something like the following:
lines = STDIN.readlines.map { |x| x.strip.to_i }.sort
puts lines.join(', ')
It's cleaner, more rubyish and faster (read the documentation for Enumerable.sort_by to see why sort is a better alternative to sort_by).
I also see your code expects a number that says how many lines to read. You can get the same behavior by modifying the example above as follows:
line_count = gets.strip.to_i
lines = (1..line_count).collect { gets.strip.to_i }.sort
puts lines.join(', ')
Try the sort function on Array's think it does what you need.

What does 'yield called out of block' mean in Ruby?

I'm new to Ruby, and I'm trying the following:
mySet = numOfCuts.times.map{ rand(seqLength) }
but I get the 'yield called out of block' error. I'm not sure what his means. BTW, this question is part of a more general question I asked here.
The problem is that the times method expects to get a block that it will yield control to. However you haven't passed a block to it. There are two ways to solve this. The first is to not use times:
mySet = (1..numOfCuts).map{ rand(seqLength) }
or else pass a block to it:
mySet = []
numOfCuts.times {mySet.push( rand(seqLength) )}
if "numOfCuts" is an integer,
5.times.foo
is invalid
"times" expects a block.
5.times{ code here }
You're combining functions that don't seem to make sense -- if numOfCuts is an integer, then just using times and a block will run the block that many times (though it only returns the original integer:
irb(main):089:0> 2.times {|x| puts x}
0
1
2
map is a function that works on ranges and arrays and returns an array:
irb(main):092:0> (1..3).map { |x| puts x; x+1 }
1
2
3
[2, 3, 4]
I'm not sure what you're trying to achieve with the code - what are you trying to do? (as opposed to asking specifically about what appears to be invalid syntax)
Bingo, I just found out what this is. Its a JRuby bug.
Under MRI
>> 3.times.map
=> [0, 1, 2]
>>
Under JRuby
irb(main):001:0> 3.times.map
LocalJumpError: yield called out of block
from (irb):2:in `times'
from (irb):2:in `signal_status'
irb(main):002:0>
Now, I don't know if MRI (the standard Ruby implementation) is doing the right thing here. It probably should complain that this does not make sense, but when n.times is called in MRI it returns an Enumerator, whereas Jruby complains that it needs a block.
Integer.times expects a block. The error message means the yield statement inside the times method can not be called because you did not give it a block.
As for your code, I think what you are looking for is a range:
(1..5).map{ do something }
Here is thy rubydoc for the Integer.times and Range.

Resources