Is this even possible with a switch case? I looked at the post here, but it's not adaptable.
step = 'a'
arr = ['a', 'b', 'c']
case step
when arr.include?
puts "var is included in array"
when "other"
puts "nothing"
end
when clauses can accept multiple values:
case step
when *arr
puts "var is included in array"
when "other"
puts "nothing"
end
This option deserves to be mentioned:
step = 'a'
arr = ['a', 'b', 'c']
case
when arr.include?(step)
puts "arr matches"
when arr2.include?(step)
puts "arr2 matches"
end
You can supply a proc to a case statement:
case step
when ->(x){ arr.include?(x) }
puts "var is included"
when "other"
puts "nothing"
end
This works because ruby uses the === operator to determine equality in a case statement, and Proc#=== executes the proc using the compared value as an argument. So:
arr = [1,2,3]
proc = ->(x){ arr.include?(x) }
proc === 2 #=> true
...although I rather like #Chuck's splat operator for this particular situation.
Related
I have the following situation:
type = "stringX"
someArray = ["stringX", "string1", "string2"]
case type
when "stringA"
puts "a"
when "stringB"
puts "b"
when someArray.any? { |x| x.include?(type) }
puts "x"
when "stringC"
puts "c"
end
What I was expecting to happen was that it would go through the case and once it evaluates the .any? method as true (because by itself it does evaluate to true), it would puts "x". However, that's not what's happening here, it just goes through the rest of the case and reaches a raise somewhere below that.
I'm wondering what's going on here?
Use * operator
value = "stringX"
some_array = ["stringX", "string1", "string2"]
case type
when "stringA"
puts "a"
when "stringB"
puts "b"
when *some_array # notice the * before the variable name!
puts "x"
when "stringC"
puts "c"
end
How does this work?
when *some_array checks whether value is an element in some_array
For this particular case one should use the brilliant answer by #akuhn
Whether you need to put any random condition inside the case, you can do it using Proc#===:
type = "stringX"
someArray = ["stringX", "string1", "string2"]
case type
when "stringA" then puts "a"
when "stringB" then puts "b"
# ⇓⇓⇓⇓⇓⇓⇓⇓ HERE
when ->(type) { someArray.any? { |x| x.include?(type) } }
puts "x"
when "stringC" then puts "c"
end
EDIT: I will not delete the answer, because I think there might be something in it you didn't know before, but it does not work for your usecase. For that you should look at mudasobwas answer
It does not quite work this way, because basically the case statement will compare the given object with the object(s) passed to when, about similar to this:
if type == "stringA"
# ...
elsif type == "stringB"
# ...
and so on, unless you use an empty case statement.
case
when type == "stringA"
# ...
This is similar to an if elsif statement though, so you don't really see that very often.
In your case however, we can make use of Ruby's splat operator
case type
when "stringA"
puts "a"
when "stringB"
puts "b"
when *someArray
puts "x"
when "stringC"
puts "c"
Ruby's case statement can take multiple arguments with when which kind of works like an "or"
case "A"
when "B"
puts "B"
when "C", "A"
puts "C or A"
end
# => C or A
and the splat operator will fan out your array:
p ["a", "b"]
# => ["a", "b"]
p *["a", "b"]
# => "a"
# => "b"
p "a", "b"
# => "a"
# => "b"
Let's say I have a array:
newArray = Array.[]
And then I push some strings in it:
newArray.push 'nil'
newArray.push 'nil2'
newArray.push 'nil3'
Now I make a while loop:
while true
load = gets.chomp
if newArray[].include? load
puts 'That pieace of the Array is loaded'
break
end
end
The part if newArray[].include? load is wrong, I know. But how can I make it so this will work?
Your question is confusing, and your code isn't idiomatic Ruby. Consider writing it like:
new_array = []
new_array << 'nil'
new_array << 'nil2'
new_array << 'nil3'
loop do
load = gets.chomp
if new_array.include? load
puts 'That piece of the Array is loaded'
break
end
end
We use snake_case_for_variables becauseItIsALotEasierToRead.
While we can write Array.new or Array.[], we seldom do. We usually assign [] to a variable instead.
We typically push to an array using <<. It's shorter to type, and visually sets apart what's happening.
Use loop do instead of while true.
I'd actually be more straightforward when defining that array:
new_array = %w[nil nil2 nil3]
And I'd use more mnemonic variable names so the code is more self-documenting:
ary = %w[nil nil2 nil3]
loop do
user_input = gets.chomp
if ary.include? user_input
puts 'That piece of the Array is loaded'
break
end
end
If you want to see if the value entered is part of a string element in the array:
if ary.any? { |s| s[user_input] }
puts 'That piece of the Array is loaded'
break
end
If you want to see if the value entered is the last character of a string element in the array:
if ary.any? { |s| s[-1] == user_input }
or:
if ary.any? { |s| s[/#{ user_input }$/] }
Read the documentation for any? to understand what it's doing.
Say I want to puts the alphabet. So I can do something like:
alphabet = ('a'..'z')
alphabet.map do |a|
puts a
end
What I want to do now is exclude the vowels.
alphabet = ('a'..'z')
vowels = ['a','e','i','o','u']
alphabet.map do |a|
puts a unless a == vowels
end
I am trying to avoid this:
alphabet = ('a'..'z')
alphabet.map do |a|
puts a unless a == 'a'
puts a unless a == 'e'
puts a unless a == 'i'
puts a unless a == 'o'
puts a unless a == 'u'
end
How do I syntactically implement the second example so that it works properly?
A Range can be expanded into an Array. Then you can subtract another array.
chars = ('a'..'z').to_a - %w( a e i o u )
chars.each do |a|
puts a
end
As a side note, don't use #map unless you really need to. Use #each if you don't care about the returning value.
You don't want equality, you want inclusion:
puts a if vowels.include? a
Also, you're using map (same as collect) which will actually return the results of the puts statements. Unless you actually need that, use each. Or find the letters that match the condition and use that collection to print the results later.
Use the Array#include? method:
puts a unless vowels.include? a
Source: http://rubydoc.info/stdlib/core/1.9.2/Array#include%3F-instance_method
You can even get rid of the loop. This preserves the original alphabet.
alphabet = ('a'..'z')
puts (alphabet.to_a - %w(a e i o u)).join('\r')
Enumerable#grep would work, too:
('a'..'z').grep(/[^aeiou]/) { |a| puts a }
Or simply
puts ('a'..'z').grep(/[^aeiou]/)
I know about Object#tap, which takes a value and returns that value. But is there a method that takes a block and returns the value evaluated by the block?
To improve my code in this answer (which is more complicated than the snippet below), I'd like to change
deck.index("A").tap {|index|
STDERR.puts "Result of indexing for #{"A".inspect} is #{index.inspect}"
}
, which has "A" repeated, into
def my_method(*args)
yield *args
end
deck = ['A', 'B', 'C']
my_method("A") {|value| deck.index(value).tap {|index|
STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }
# Result of indexing for "A" is 0
# => 0
What you're looking for is essentially the equivalent of let in Lisp or OCaml — something that allows you to temporarily bind a value to an identifier without introducing a new variable into the larger scope. There isn't anything that lets you do such a thing with that syntax in Ruby. The equivalent Ruby would be:
lambda {|value| deck.index(value).tap {|index|
STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }.call 'A'
You could of course just write a method like:
def let(*values)
yield *values
end
I think you could solve it with fibers. Something like:
def myfiber
block = lambda{nil}
loop{ block = Fiber.yield(block.call) }
end
f = Fiber.new {myfiber }
f.resume
puts "result: #{f.resume(lambda{1})}"
puts "result: #{f.resume(lambda{5})}"
puts "result: #{f.resume(lambda{2})}"
will result in:
result: 1
result: 5
result: 2
How can I do something like this ? or do i need to use IF all the time?
ar = [["a","b"],["c"],["d","e"]]
x = "b"
case x
when ar[0].include?(x)
puts "do something"
when ar[1].include?(x)
puts "do else"
when ar[2].include?(x)
puts "do a 3rd thing"
end
I'm using ruby 1.8.7
It's not only possible, it's easy. For constant arrays:
#!/usr/bin/ruby1.8
x = "a"
case x
when 'a', 'b'
puts "do something" # => do something
when 'c'
puts "do else"
when 'd', 'e'
puts "do a 3rd thing"
end
Or, if the arrays aren't constant:
#!/usr/bin/ruby1.8
ar = [["a","b"],["c"],["d","e"]]
x = 'd'
case x
when *ar[0]
puts "do something"
when *ar[1]
puts "do else"
when *ar[2]
puts "do a 3rd thing" # => do a 3rd thing
end
Why don't you restructure you code a bit and do
ar = [["a","b"],["c"],["d","e"]]
x = "b"
i = (0...ar.length).find {|i| ar[i].include?(x)}
case i
when 0
puts "do something"
when 1
puts "do else"
when 2
puts "do a 3rd thing"
end