How to create array name after value of variable - ruby

I'm trying to create some arrays in some threads and name them after a fixnum between 1 and 30 like the following:
times = 30
n=0
thread = []
while n < times
thread << Thread.new(n) {|x|
array#{x} = Array.new()
...
}
end
How can I do that?

Ruby does not allow you to create variable names from strings in the same way that PHP does. In a case such as this you could use an array or a hash instead.
times = 30
n=0
arrays = []
thread = []
while n < times
thread << Thread.new(n) {|x|
arrays[x] = Array.new()
...
}
end
You can also use more rubyish constructs instead of while, such as Fixnum#times.
arrays = []
threads = 30.times.map do |n|
Thread.new do
arrays[x] = Array.new
# ...
end
end
> arrays
#=> [[], [], [], ....]
> threads
#=> [#<Thread:0x007fe3f22a2320 dead>, #<Thread:0x007fe3f22a2208 dead>, ...]

If you don't mind using instance variables rather than local variables, you can do what you are trying to do (whether it is a good idea to design code in this way is another question).
1.upto(times) do |i|
instance_variable_set("#array#{i}".to_sym, [])
end

Related

How to find count matching characters at the same indes and at an unmatching index

I have built a version of mastermind that checks a user's input and provides feedback based on how close the user's guess was to the winning sequence. If you're not familiar with the game, you get feedback indicating how many of your characters were guessed correctly at the same index and how many characters guessed are in the sequence, but at the wrong index. If there are duplicates in the guess, then you would not count the extra values unless they correspond to the same number of duplicates in the secret code.
Example: If the sequence is ["G","G","G","Y"] and the user guesses ["G", "Y","G","G"] then you'd want to return 2 for items at the same index and 2 for items at different indexes that are included in the secret sequence.
Another example: If the sequence is ["X","R","Y","T"] and the user guesses ["T","T","Y","Y"] then you'd return 1 for items at the same index 1 for the character guessed that is in the sequence but at the wrong index.
Anyway, to me this is not a simple problem to solve. Here's the code I used to get it to work, but it's not elegant. There must be a better way. I was hoping someone can tell me what I'm missing here?? New to Ruby...
def index_checker(input_array, sequence_array)
count = 0
leftover_input = []
leftover_sequence = []
input.each_with_index do |char, idx|
if char == sequence[idx]
count += 1
else
leftover_input << char
leftover_sequence << sequence[idx]
end
end
diff_index_checker(leftover_input, leftover_sequence, count)
end
def diff_index_checker(input, sequence, count)
count2 = 0
already_counted = []
input.each do |char|
if sequence.include?(char) && !already_counted.include?(char)
count2 += 1
already_counted << char
end
end
[count, count2]
end
Here's a clean Ruby solution, written in idiomatic Ruby object-oriented style:
class Mastermind
def initialize(input_array, sequence_array)
#input_array = input_array
#sequence_array = sequence_array
end
def matches
[index_matches, other_matches]
end
def results
[index_matches.size, other_matches.size]
end
private
attr_reader :input_array, :sequence_array
def index_matches
input_array.select.with_index { |e, i| e == sequence_array[i] }
end
def other_matches
non_exact_input & non_exact_sequence
end
def non_exact_input
array_difference(input_array, index_matches)
end
def non_exact_sequence
array_difference(sequence_array, index_matches)
end
# This method is based on https://stackoverflow.com/a/3852809/5961578
def array_difference(array_1, array_2)
counts = array_2.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
array_1.reject { |e| counts[e] -= 1 unless counts[e].zero? }
end
end
You would use this class as follows:
>> input_array = ["G","G","G","Y"]
>> sequence_array = ["G", "Y","G","G"]
>> guess = Mastermind.new(input_array, sequence_array)
>> guess.results
#> [2, 2]
>> guess.matches
#> [["G", "G"], ["G", "Y"]]
Here's how it works. First everything goes into a class called Mastermind. We create a constructor for the class (which in Ruby is a method called initialize) and we have it accept two arguments: input array (the user guess), and sequence array (the answer).
We set each of these arguments to an instance variable, which is indicated by its beginning with #. Then we use attr_reader to create getter methods for #input_array and #sequence_array, which allows us to get the values by calling input_array and sequence_array from any instance method within the class.
We then define two public methods: matches (which returns an array of exact matches and an array of other matches (the ones that match but at the wrong index), and results (which returns a count of each of these two arrays).
Now, within the private portion of our class, we can define the guts of the logic. Each method has a specific job, and each is named to (hopefully) help a reader understand what it is doing.
index_matches returns a subset of the input_array whose elements match the sequence_array exactly.
other_matches returns a subset of the input_array whose elements do not match the sequence_array exactly, but do match at the wrong index.
other_matches relies on non_exact_input and non_exact_sequence, each of which is computed using the array_difference method, which I copied from another SO answer. (There is no convenient Ruby method that allows us to subtract one array from another without deleting duplicates).
Code
def matches(hidden, guess)
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
guess_counts = counting_hash(guess.values_at *indices_wo_match)
[hidden.size - indices_wo_match.size, guess_counts.reduce(0) { |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min }]
end
def counting_hash(arr)
arr.each_with_object(Hash.new(0)) { |s, h| h[s] += 1 }
end
Examples
matches ["G","G","G","Y"], ["G", "Y","G","G"]
#=> [2, 2]
matches ["X","R","Y","T"] , ["T","T","Y","Y"]
#=> [1, 1]
Explanation
The steps are as follows.
hidden = ["G","G","G","Y"]
guess = ["G", "Y","G","G"]
Save the indices i for which hidden[i] != guess[i].
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
#=> [1, 3]
Note that the number of indices for which the values are equal is as follows.
hidden.size - indices_wo_match.size
#=> 2
Now compute the numbers of remaining elements of guess that pair with one of the remaining values of hidden by having the same value. Begin by counting the numbers of instances of each unique element of hidden and then do the same for guess.
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
#=> {"G"=>1, "Y"=>1}
guess_counts = counting_hash(guess.values_at *indices_wo_match)
#=> {"Y"=>1, "G"=>1}
To understand how counting_hash works, see Hash::new, especially the explanation of the effect of providing a default value as an argument of new. In brief, if a hash is defined h = Hash.new(3), then if h does not have a key k, h[k] returns the default value, here 3 (the hash is not changed).
Now compute the numbers of matches of elements of guess that were not equal to the value of hidden at the same index and which pair with an element of hidden that have the same value.
val_matches = guess_counts.reduce(0) do |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min
end
#=> 2
Lastly, return the values of interest.
[hidden.size - indices_wo_match.size, val_matches]
#=> [2, 2]
In the code presented above I have substituted out the variable val_matches.
With Ruby 2.4+ one can use Enumerable#sum to replace
guess_counts.reduce(0) { |tot, (k, cnt)| tot + [hidden_counts[k], cnt].min }
with
guess_counts.sum { |k, cnt| [hidden_counts[k], cnt].min }
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
semi = secret.uniq.sum { |s| [secret.count(s), guess.count(s)].min } - full
[full, semi]
end
Demo:
> judge(["G","G","G","Y"], ["G","Y","G","G"])
=> [2, 2]
> judge(["X","R","Y","T"], ["T","T","Y","Y"])
=> [1, 1]
A shorter alternative, though I find it less clear:
full = secret.zip(guess).count(&:uniq!)
I prefer my other answer for its simplicity, but this one would be faster if someone wanted to use this for arrays larger than Mastermind's.
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
pool = secret.group_by(&:itself)
[full, guess.count { |g| pool[g]&.pop } - full]
end
Demo:
> judge(["G","G","G","Y"], ["G","Y","G","G"])
=> [2, 2]
> judge(["X","R","Y","T"], ["T","T","Y","Y"])
=> [1, 1]

Why use enumerator in ruby

I stumbled upon such example:
file = "./path"
var = Enumerator.new do |y|
CSV.foreach(file) do |row|
y.yield(row)
end
end
Question is, why store data of any kind, inside enumerators, insted of arrays? what is the difference in behaviour between whats above and this:
file = "./path"
var = []
CSV.foreach(file) do |row|
var << row
end
when i want to something with the data it looks the same for both cases:
var.each {|row| puts row}
So what are the advantages and disadvantages of such constructions?
In general, iterators can be used to lazily generate a sequence of objects.
This is the main advantage when creating a lazy enumeration compared to creating a collection of items which is much more efficient.
For example, if your enumerator loop iterates over just the first 5 items of 3 million items then that's all yield returns, and you didn't build up a collection of 1 million items internally first.
So, you do not need to load all the 3 millions items just for your callee function can continue and executes the rest of the code.
Iterators are means for returning sequences.
Sometimes The sequence might even be infinite.
It brings the functional programming concept of lazy evaluation to Ruby – at least for enumerations.
There is a huge difference between returning a collection and returning a collection generator.
Too see the difference of the code add a puts within the loops.
seq = (1..3)
enum = Enumerator.new do |y|
seq.each do |i|
puts "Grabbing #{i} with enumerator"
y.yield(i)
end
end
enum.each { |i| puts "Taken #{i} from enumerator" }
# Grabbing 1 with enumerator
# Taken 1 from enumerator
# Grabbing 2 with enumerator
# Taken 2 from enumerator
# Grabbing 3 with enumerator
# Taken 3 from enumerator
array = []
seq.each do |i|
puts "Grabbing #{i} with array"
array << i
end
array.each { |i| puts "Taken #{i} from array" }
# Grabbing 1 with array
# Grabbing 2 with array
# Grabbing 3 with array
# Taken 1 from array
# Taken 2 from array
# Taken 3 from array
Like mentioned by Tal Avissar the Enumerator fetches the value when it's needed which is called lazy evaluation. This behavoir is a benefit in some situations.
# infinite number sequence
numbers = Enumerator.new do |y|
n = 0
loop { y.yield(n += 1) }
end
puts numbers.take(3).join(', ')
# 1, 2, 3
When dealing with huge or infinite sequences the difference is quite important.

Values in the while loop do not modify outside values

I have a long code but I tried to copy and adapt my problem in as few lines as possible . I have a method which creates an array( 2D ) with 0 and 1
array1 = newValue(2) - the number 2 represents how many 1 the array has
array2 = newValue(3)
and this loop
(0..9).each do|i|
(0..9).each do|j|
while((array1[i][j] == array2[i][j]) && (array2[i][j] == 1)) do
array1 = newvalue(2)
array2 = newvalue(3)
end
end
end
I'm using the while loop so I won t have a 1 in the same position in both arrays . But what is inside the while loop doesn't modify the values of the array . I also tried using map!/collect! but I think I did something wrong because nothing happened. I hope you can understand what I was trying to do .
Edit:
def newValue(value)
value = value.to_i
array = Array.new(10) { Array.new(10 , 0) }
(a lot of conditions on how to position the items in the array)
return array
end
Here's my take... hopefully it'll help out. It seems that what you noticed was true. The arrays are not getting reset. Probably because inside the each blocks, the scope is lost. This is probably because the are arrays. I took a slightly different approach. Put everything in a class so you can have instance variables that you can control and you know where they are and that they are always the same.
I pulled out the compare_arrays function which just returns the coordinates of the match if there is one. If not it returns nil. Then, youre while loop is simplified in the reprocess method. If you found a match, reprocess until you don't have a match any more. I used a dummy newValue method that just returned another 2d array (as you suggested yours does). This seems to do the trick from what I can tell. Give it a whirl and see what you think. You can access the two arrays after all the processing with processor.array1 as you can see I did at the bottom.
# generate a random 2d array with 0's and val's
def generateRandomArray(val=1)
array = []
(0..9).each do |i|
(0..9).each do |j|
array[i] ||= []
array[i][j] = (rand > 0.1) ? 0 : val
end
end
array
end
array1 = generateRandomArray
array2 = generateRandomArray
def newValue(val)
generateRandomArray(val)
end
class Processor
attr_reader :array1, :array2
def initialize(array1, array2)
#array1 = array1
#array2 = array2
end
def compare_arrays
found = false
for ii in 0..9
break unless for jj in 0..9
if ((#array2[ii][jj] == 1) && (#array1[ii][jj] == 1))
found = true
break
end
end
end
[ii,jj] if found
end
def reprocess
while compare_arrays
puts "Reprocessing"
#array1 = newValue(2)
#array2 = newValue(3)
reprocess
end
end
end
processor = Processor.new(array1, array2)
processor.reprocess
puts processor.array1.inspect

Sort Array by Popularity and Time in Ruby

I am a Ruby Rails newbie.
Is there a way to know the popularity of elements in an Array over time?
For example lets say for the last 15 min..
The array has like ["abc", "ab", "abc", "a", "abc", "ab"........] being pushed into the array.. can we get "abc" and "ab" as the most popular ones.. just for the last 15 minutes?
If you take for an entire hour.. typical for the entire hour.."abcd" is the most popular.. it should return "abcd" as the most popular element in an array..
Is there a way to achieve this?
Create your own class which inherits from Array, or delegates all its functionality to an Array. For example:
class TimestampedArray
def initialize
#items = []
end
def <<(obj)
#items << [Time.now,obj]
end
# get all the items which were added in the last "seconds" seconds
# assumes that items are kept in order of add time
def all_from_last(seconds)
go_back_to = Time.now - seconds
result = []
#items.reverse_each do |(time,item)|
break if time < go_back_to
result.unshift(item)
end
result
end
end
If you have an old version of Ruby, which doesn't have reverse_each:
def all_from_last(seconds)
go_back_to = Time.now - seconds
result = []
(#items.length-1).downto(0) do |i|
time,item = #items[i]
break if time < go_back_to
result.unshift(item)
end
result
end
Then you need something to find the "most popular" item. I often use this utility function:
module Enumerable
def to_histogram
result = Hash.new(0)
each { |x| result[x] += 1 }
result
end
end
On which you could base:
module Enumerable
def most_popular
h = self.to_histogram
max_by { |x| h[x] }
end
end
So then you get:
timestamped_array.all_from_last(3600).most_popular # "most popular" in last 1 hour

How would you implement this idiom in ruby?

As someone who came from Java background and being a newbie to Ruby,
I was wondering if there is a simple way of doing this with ruby.
new_values = foo(bar)
if new_values
if arr
arr << new_values
else
arr = new_values
end
end
Assuming "arr" is either an array or nil, I would use:
arr ||= []
arr << new_values
If you're doing this in a loop or some such, there might be more idiomatic ways to do it. For example, if you're iterating a list, passing each value to foo(), and constructing an array of results, you could just use:
arr = bars.map {|bar| foo(bar) }
If I'm understanding you correctly, I would probably do:
# Start with an empty array if it hasn't already been set
#arr ||= []
# Add the values to the array as elements
#arr.concat foo(bar)
If you use #arr << values you are adding the entire array of values to the end of the array as a single nested entry.
arr = [*arr.to_a + [*new_values.to_a]]
Start with:
arr ||= []
And then, depending on whether new_values is an array or not
arr += new_values # if array
arr << new_values # if not
arr += [*new_values] # if it could be either
Furthermore, you can get rid of the test on new_values by taking advantage of the fact that NilClass implements a .to_a => [] method and reduce everything to:
arry ||= []
arr += [*new_values.to_a]
But wait, we can use that trick again and make the entire thing into a one-liner:
arr = [*arr.to_a + [*new_values.to_a]]
I don't intend to write an inexcrutable one-liner, but I think this is quite clear. Assuming, as Phrogz, that what you really need is an extend (concat):
arr = (arr || []).concat(foo(bar) || [])
Or:
(arr ||= []).concat(foo(bar) || [])
I would use:
new_values = foo(bar)
arr ||= []
arr << new_values if new_values

Resources