Rails: random unique array of fixed length - ruby-on-rails

How can I ensure uniqueness in this array while maintaining its length at 5?
def fixed
5.times.collect { SecureRandom.random_number(10) }
end
This behaviour seems odd:
5.times.collect.uniq { SecureRandom.random_number(10) }
# => [0, 2, 3, 4]
5.times.collect.uniq { SecureRandom.random_number(10) }
# => [0, 1, 3]
5.times.collect.uniq { SecureRandom.random_number(10) }
# => [0, 1, 2, 3, 4]
5.times.collect.uniq { SecureRandom.random_number(10) }
# => [0, 1, 2, 4]
5.times.collect.uniq { SecureRandom.random_number(10) }
# => [0, 1, 2, 3]

When the number of possible values is small – like 10 in your example – then I would generate an array with all options and just pick a random sample of entries:
(0..9).to_a.sample(5)
If the number of possible values is huge then generation all values first is certainly not an option. Then I would generate a random value as long as the array doesn't contain enough entries:
require 'set'
values = Set.new
until values.length == 5 do
values.add(SecureRandom.random_number(1_000_000))
end
values.to_a
Note the I am using a Set to ensure the uniqueness of the values in the second version.

Using SecureRandom
def fixed
unique_numbers = []
5.times.collect do
loop do
number = SecureRandom.random_number(10)
break number unless unique_numbers.include?(number)
end
end
end
And if you want to generate unique numbers between 1 to 10, then you can create array of 1 to 10 and use shuffle or sample to get random numbers.
Using shuffle
> (0...10).to_a.shuffle.take(5)
=> [4, 0, 1, 3, 7]
> (0...10).to_a.shuffle.take(5)
=> [6, 2, 3, 9, 1]
> (0...10).to_a.shuffle.take(5)
=> [9, 2, 5, 8, 4]
> (0...10).to_a.shuffle.take(5)
=> [5, 0, 6, 8, 7]
> (0...10).to_a.shuffle.take(5)
=> [2, 7, 1, 5, 0]
Using sample
> (1..10).to_a.sample(5)
=> [4, 6, 3, 2, 7]
> (1..10).to_a.sample(5)
=> [5, 8, 2, 3, 7]
> (1..10).to_a.sample(5)
=> [2, 5, 6, 1, 3]
> (1..10).to_a.sample(5)
=> [8, 5, 10, 9, 3]
> (1..10).to_a.sample(5)
=> [8, 1, 5, 3, 4]
You can also pass SecureRandom custom random generator as an argument with sample
> (1..10).to_a.sample(5, random: SecureRandom)
=> [6, 3, 4, 7, 10]
> (1..10).to_a.sample(5, random: SecureRandom)
=> [7, 4, 8, 1, 5]
> (1..10).to_a.sample(5, random: SecureRandom)
=> [8, 3, 9, 5, 10]
> (1..10).to_a.sample(5, random: SecureRandom)
=> [6, 8, 9, 2, 1]
> (1..10).to_a.sample(5, random: SecureRandom)
=> [9, 10, 1, 8, 2]

Just out of curiosity, using Enumerable#cycle infinite generator.
MAX = 10
SIZE = 5
[MAX].cycle.inject(Set.new) do |acc, max|
break acc if acc.size >= SIZE
acc << SecureRandom.random_number(max)
end
#⇒ #<Set: {2, 1, 7, 0, 9}>
or even with generic loop:
loop.each_with_object(Set.new) do |_, acc|
break acc if acc.size >= SIZE
acc << SecureRandom.random_number(10)
end
#⇒ #<Set: {2, 6, 7, 1, 3}>

One way would be to generate a range of numbers from 0 to 10 and
then shuffle them to get the unique random numbers.
You can convert that range to Array using to_a and shuffle them using shuffle
You can do something like this:
(0..10).to_a.shuffle[0..4] # => [8, 6, 1, 9, 10]
[0..4] will give you the first 5 shuffled elements.

Related

ruby/rails array all elements between two indices

I have an array like this: [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
What's the simplest way to return each item in the array from position 6 until 0 where the resulting array looks like: [1,2,3,4,5,6,7]
This positions in the array can be dynamic, for example passing in 4 and 9 should return [11,12,1,2,3,4]
I'm wondering if there's a method that accomplishes this in Rails api.
Thanks in advance
EDIT
Let's assume that no negative numbers, so doing array[2..-2] wont work.
Array#splice almost works for this, but if the second position is less than the first, it returns nil.
def foo a, min, max
a.rotate(min).first((max - min) % a.length + 1)
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
foo(a, 6, 0) # => [1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
class Array
def get_sub_array(start,last)
(start > last) ? (self[start..-1] + self[0..last]) : self[start..last]
end
end
Then
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
a.get_sub_array(6,0)
#[1, 2, 3, 4, 5, 6, 7]
Or if you don't want to monkey patch
You could have a method like
def get_sub_array(array, start,last)
(start > last) ? (array[start..-1] + array[0..last]) : array[start..last]
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
get_sub_array(a,6,0)
#[1, 2, 3, 4, 5, 6, 7]
def some_function(some_array,start_val=6, end_val=0)
if end_val > start_val
some_array[start_val,(end_val - start_val)]
else
(some_array[start_val, some_array.size] << some_array[0, (end_val)]).flatten
end
end
You can use ternary operator to make it one liner too:
def some_function(some_array,start_val=6, end_val=0)
end_val > start_val ? some_array[start_val,(end_val - start_val)] : (some_array[start_val, some_array.size] << some_array[0, (end_val)]).flatten
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
some_function(a) # => [1, 2, 3, 4, 5, 6, 7]
some_function(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
min=6
max=0
arr = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
result = []
if max<min
result << arr[min..arr.length]
result << arr[0..max]
else
result << arr[min..max]
end
A couple more ways (my preference being for #1).
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
#1
def foo a, min, max
as = a.size
max += as if max < min
(min..max).map { |i| a[i%as] }
end
foo(a, 6, 0) # => [ 1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
#2
def foo a, min, max
max += a.size if max < min
e = a.cycle
min.times { e.next }
(max-min+1).times.map { e.next }
end
foo(a, 6, 0) # => [ 1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
def foo a, s, e
a = e < s ? (a[s,a.size] << a[0..e]).flatten : a[s..e]
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
a = foo(a, 6, 0) # => [1, 2, 3, 4, 5, 6, 7]
a = foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
myArray = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
myArray[6..-1] returns [1, 2, 3, 4, 5, 6]
myArray[4..9] returns [11,12,1,2,3,4]

Find a value in common in two two-dimensionals arrays Ruby

I have two arrays, and each is two dimensional, I want to take the value of array 1 in position i and try to find the same value in array 2. If they have the same value, the values of array 2 in x position is concatenated in array 1 in position i.
example
Array 1
[[1,2,3,4,5,6],[3,5,7,2,12,5],[a,f,3,d,4,g]]
Array 2
[[b,e,w,1,4,6] , [1,0,8,5,8,9]]
So the new array 1 will be
[[1,2,3,4,5,6,1,0,8,5,8,9],[3,5,7,2,12,5],[a,f,3,d,4,g]]
Any thought.....
Your description of the task isn't correct. You can't
take the value of the array 1 in position i
because array 1 contain arrays itself, so you can take value in position i, j. And search for same values in array 2 in each i on position j. And if this is what you want, here is sample code:
arr_1 = [[1, 2, 3, 4, 5, 6], [3, 5, 7, 2, 12, 5], ['a', 'f', 3, 'd', 4, 'g']]
arr_2 = [['b', 'e', 'w', 1, 4, 6], [1, 0, 8, 5, 8, 9]]
search_i = 0
search_j = 0
search_val = arr_1[search_i][search_j]
arr_2.each_with_index do |val_i, i|
val_i.each_with_index do |val_j, j|
if j == search_j && arr_2[i][j] == search_val
arr_1[search_i].concat(arr_2[i])
end
end
end
p arr_1 # [[1, 2, 3, 4, 5, 6, 1, 0, 8, 5, 8, 9], [3, 5, 7, 2, 12, 5], ["a", "f", 3, "d", 4, "g"]]

Is it possible to get the difference from two dynamic arrays regardless of their order?

If I have two arrays and I try to find their difference..
[1, 2, 3, 2, 6, 7] - [2, 1]
I get :
[3, 6, 7]
But if I flip those arrays around
[2, 1] - [1, 2, 3, 2, 6, 7]
I get :
[]
My question is, being that my two arrays are dynamic, I need to know if there is a difference in between both arrays regardless of their order. What's the simplest expression to find that?
You can define it:
class Array
def diff(o)
(o - self) + (self - o) # alternatively: (o + self) - (o & self)
end
end
[2, 1].diff [1, 2, 3, 2, 6, 7] # [3, 6, 7]
[1, 2, 3, 2, 6, 7].diff [2, 1] # [3, 6, 7]
[2, 3, 3, 1].diff [2, 4, 5] # [4, 5, 3, 3, 1]
[2, 4, 5].diff [2, 3, 3, 1] # [3, 3, 1, 4, 5]
The correct answer probably depends on what you want in the end, though, as the second two examples above show.
If you only want unique values, you'll want to convert the two inputs to sets first, and return the result as an array:
class Array
def diff(o)
(o.to_set ^ to_set).to_a # or simply (o.to_set ^ self).to_a
end
end
[2, 4, 5].diff [2, 3, 3, 1] # [4, 5, 3, 1]
(There might be a built-in Rails method, too.)
Using Set#^:
require 'set'
([2, 1].to_set ^ [1, 2, 3, 2, 6, 7]).to_a
# => [3, 6, 7]
([1, 2, 3, 2, 6, 7].to_set ^ [2, 1]).to_a
# => [3, 6, 7]
According to the documentation:
Set#^ returns a new set containing elements exclusive between the set and
the given enumerable object.

A more balanced array manipulation than each_slice?

I have an array of 10 items and I want to split it up into 3 sections that look like this:
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
Using each_slice I can get close:
a = *(1..10)
a.each_slice(4) # use 4 so I can fit everything into 3 sections
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10]
But I want the first format which is more evenly distributed. I can do it writing my own method. But is there a built in way to do this in ruby 1.9+?
Update:
Since there's no built in way I'd like to change my question to - how would you implement it?
Here's my implementation
def chunk(a, pieces)
size = a.size / pieces
extra = a.size % pieces
chunks = []
start = 0
1.upto(pieces) do |i|
last = (i <= extra) ? size.next : size
chunks << a.slice(start, last)
start = chunks.flatten.size
end
chunks
end
call it like so
a = *(1..10)
puts chunk(a, 3)
will output
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
If piece size is too big it pads with empty arrays
a = *(1..10)
puts chunk(a, 14)
will output
[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [], [], [], []]

How to Line Chart this data?

I would like to create line chart for following data. I would also like to have the ability to hover over each data point to look at the x and y value at that data point. I have the following data structure:
x[0] = [23 4 2 2 4 4 5 3 334 2]
y[0] = [6 24 1 2 2 5 1 3 8 0]
x[1] = [5 6 8 6 3 4 6 3 3]
y[1] = [9 7 8 6 3 4 1 9 2]
x[2] = [6 9 9 6 2 5 8 3]
y[2] = [1 0 2 5 6 2 1 5]
... so that I will have 3 lines on the same chart.
I played with "Seer" without much success. Can anyone provide any recommendations / examples / references for plotting similar data using Seer or anything else?
Thanks.
Give the lazy_high_charts gem a try.
#app/views/layouts/appliction.*
= javascript_include_tag 'highcharts.js'
#Gemfile
gem 'lazy_high_charts'
# my_controller#my_action
x_0 = [23, 4, 2, 2, 4, 4, 5, 3, 334, 2]
y_0= [6, 24, 1, 2, 2, 5, 1, 3, 8, 0]
x_1 = [5, 6, 8, 6, 3, 4, 6, 3, 3]
y_1 = [9, 7, 8, 6, 3, 4, 1, 9, 2]
x_2 = [6, 9, 9, 6, 2, 5, 8, 3]
y_2 = [1, 0, 2, 5, 6, 2, 1, 5]
data_0 = x_0.zip(y_0)
data_1 = x_1.zip(y_1)
data_2 = x_2.zip(y_2)
#h = LazyHighCharts::HighChart.new('graph') do |f|
f.series(:name => "xy0", :data => data_0)
f.series(:name => "xy1", :data => data_1)
f.series(:name => "xy3", :data => data_2)
f.chart({:defaultSeriesType=>"line" })
f.yAxis(:title => { :text => "y axis values" } )
f.xAxis(:title => { :text => "x axis values"} )
f.title(:text => "XY Graph")
f.plotOptions({}) # override the default values that lazy_high_charts puts there
f.legend({}) # override the default values
end
#app/views/my_controller/my_action
= high_chart("chart", #h)
Caveat:
HighCharts is only free for non-commercial use. That may or may not be a dealbreaker for you.
I've really liked jQuery flot for this kind of thing:
http://code.google.com/p/flot/
Check out the example here:
http://flot.googlecode.com/svn/trunk/README.txt
In your controller or view, you can use Ruby's zip to zip together arrays of x and y values if you need to:
> a = [1,2,3]
=> [1, 2, 3]
> b = [5,6,7]
=> [5, 6, 7]
> a.zip(b)
=> [[1, 5], [2, 6], [3, 7]]

Resources