I have the following code:
sentence_array = ["hello", "hi", "bonjour"]
I'd like to be able to output the word that's the longest of the 3 elements. I know I should probably use sentence_array.each but I'm stuck on how to proceed.
sentence_array.max_by(&:length)
The enumerable module is one you will learn to love.
This is one way:
sentence_array.sort_by {|e| e.length} .last
#=> "bonjour"
Related
I need a function to check if an array contains other arrays, or more generally if an array contains a certain class. My naive first approach is:
found=false
[1,"a",[],:asdf].each { |x| found=(x.is_a? Array) ? true : found }
puts found
Any way to optimize this?
In newer Rubies (2.5+) you don't need to pass a block to any?. That links goes to the latest docs, which has a similar example checking for integers.
Therefore, you can simply use:
[1, "a", [], :asdf].any?(Array)
# => true
[1, "a", :asdf].any?(Array)
# => false
That seems the simplest syntax and most sensible approach here if your Ruby version allows it :)
You can try #any?
For example:
[1,"a",[],:asdf].any? { |el| el.is_a? Array }
#=> true
Almost always when you find yourself using each, you are missing some higher-level abstraction.
In this case, that abstraction is the method Array#any?, which will return true if any element of the array satisfies the predicate:
[1, "a", [], :asdf].any?(Array)
this approach iterate over all elements even if you found an array.
in your test case it will iterate over :asdf,
and you don't have to check this.
I think you need to break from loop if you found the certain type(Array in our Example).
found = false
[1,"a",[],:asdf].each do |x|
if x.is_a? Array
found = true
break
end
end
puts found
Also you can use any instead of each
found = [1,"a",[],:asdf].any? { |x| x.is_a? Array }
puts found # true
I know that I can use
my_array = [1,2,3,4,5]
my_array.each {|element| puts element}
to do something with each element of an array but what if I need to do several things with each element? It starts complaining when I try to put multiple statements in the block. What I am really looking for is something more like this:
my_array = [1,2,3,4,5]
my_array.each |element| do
#operation one involving the element
#operation two involving the element
...
end
Is there any good way to achieve this effect?
You can put as many statements as you like inside a block, but you need to get the do/end syntax right.
The order is do |elemenet|, not |element| do. The do/end keywords replace the {}.
my_array.each do |element|
puts "element is #{element}"
element += 1
puts "Now element is #{element}"
# etc...
end
If you really want to cram it into a one liner you can use semicolons.
x = [1,2,3,4,5]
x.map{|y| y*=2; y-=5; y}
This gives you:
=> [-3, -1, 1, 3, 5]
It gets pretty ugly pretty fast though, so use multiliners unless there's a really good reason you want it on one line.
Let's say I have an array
arry = ["a","b","c","d","e","f","g"]
and I want to get the fourth, second, and seventh element of that array.
Let's say some other function determined which are the needed values and passed me backan array of indices like [3, 1, 6]. In most languages I could write this
array[3,1,6] #=> ["d","b","g"] (or "dbg"?)
or
array[3 1 6] #=> ["d","b","g"]
But that won't work in Ruby, of course. Is there a simple way to do this in Ruby? The cleanest I can find is something like:
[3,1,6].map { |i| array[i] }
I really tried to find a duplicate to this question since it seems so basic, but I just couldn't.
This is remarkably easy to do in most languages, so I'm almost assuming I'm just overlooking the remarkably obvious.
array.values_at(3,1,6) #=> ["d","b","g"]
If your other function returns an array then you must flatten it before you can pass it as parameters to values_at. Like this
arry = ["a","b","c","d","e","f","g"]
def indices
[1,3,6]
end
puts arry.values_at(*indices)
output
b
d
g
what is your version to this problem ?
i'm doing so:
array = [1,2,3,4,5,6,7,8,9]
puts array.sort_by { array }.first
puts array[rand(array.size)]
puts array.shuffle.first
puts array.sample
I use array.sample. It is MUCH easier to read than the first 2 and slightly easier to read than the third.
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.