Detect which elements were added to an array in ruby [duplicate] - ruby-on-rails

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
diff a ruby string or array
I have an old array: [1, 2, 3, 4, 5], and new: [1, 2, 4, 6]
How to get difference with Ruby: that 5, 3 was removed and 6 was added?

irb(main):001:0> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> b = [1, 2, 4, 6]
=> [1, 2, 4, 6]
irb(main):003:0> a - b
=> [3, 5]
irb(main):005:0> b - a
=> [6]
irb(main):006:0>

Related

How to split array to sub-arrays of elements with same values ? (ruby) [duplicate]

This question already has answers here:
Ruby - collect same numbers from array into array of arrays
(4 answers)
Closed 2 years ago.
I have the array [1, 2, 2, 2, 3, 4, 4, 5, 6]
Is there any elegant way I can split it to sub-arrays, so that each array contains elements with same values?
I want to achieve the following result:
result = [[1], [2, 2, 2], [3], [4, 4], [5], [6]]
Thank you for your help !
Input
a = [1, 2, 2, 2, 3, 4, 4, 5, 6]
Code
p a.slice_when { |a, b| a != b }.to_a
output
[[1], [2, 2, 2], [3], [4, 4], [5], [6]]

Is there an alternative to use of the method Array#product? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am using the method Array#product with several arguments that are large arrays. The receiver is also a large array. Consequently, the resulting array is huge and consumes an excessive amount of memory. I need all the combinations produced but I don't need them in a single array.
I would like to know if there is an alternative to using that method that requires less memory. Computational time is not really an issue.
You can use the block form of product (see https://apidock.com/ruby/Array/product).
For example the following makes my ruby process unresponsive and I have to kill -9 it:
list = Array.new(100_000)
list.product list
However with the block form I can control+c to stop it any time:
list.product(list) do |combination|
puts combination.join(",")
end
Let me begin with the problem of computing the product of two arrays. Later I will address the more general problem.
arr1 = [1,2,3]
arr2 = [4,5,6]
arr1.product(arr2)
#=> [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5],
# [2, 6], [3, 4], [3, 5], [3, 6]]
To reduce memory requirements--that is, avoiding the construction of the above array--you can construct an enumerator.
product_enum = Enumerator.new do |y|
arr1.size.times do |i|
e1 = arr1[i]
arr2.size.times { |j| y << [e1, arr2[j]] }
end
end
#=> #<Enumerator: 3<Enumerator::Generator:0x00...20>:each>
loop do
p product_enum.next
end
[1, 4]
[1, 5]
[1, 6]
[2, 4]
[2, 5]
[2, 6]
[3, 4]
[3, 5]
[3, 6]
To reuse the enumerator execute product_enum.rewind. See Enumerator::new and Enumerator#rewind. Enumerator::new's block variable y is called a yielder. An enumerator can be thought of as a machine that generates values following certain rules.
Ruby's methods Array#combination, Array#permutation and others return enumerators, but for reasons that are unknown to me, Array#product returns an array. (Perhaps a reader can explain why in a comment.)
We can construct an Array method product_enum that returns an enumerator, which you could use for your problem.
class Array
def product_enum(*arr)
Enumerator.new do |y|
self.size.times do |i|
e1 = self[i]
product_enum_recurse(y,[e1],*arr)
end
end
end
def product_enum_recurse(y,a,*arr)
v, *rest = arr
v.size.times do |i|
if rest.empty?
y << [*a, v[i]]
else
product_enum_recurse(y,[*a, v[i]],*rest)
end
end
end
end
e = [1,2].product_enum([3,4], [5,6], [7,8])
#=> #<Enumerator: #<Enumerator::Generator:0x00...0>:each>
loop do
p e.next
end
[1, 3, 5, 7]
[1, 3, 5, 8]
[1, 3, 6, 7]
[1, 3, 6, 8]
[1, 4, 5, 7]
[1, 4, 5, 8]
[1, 4, 6, 7]
[1, 4, 6, 8]
[2, 3, 5, 7]
[2, 3, 5, 8]
[2, 3, 6, 7]
[2, 3, 6, 8]
[2, 4, 5, 7]
[2, 4, 5, 8]
[2, 4, 6, 7]
[2, 4, 6, 8]

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.

How do I repeat certain items in an array based on matched values in another array?

I've been trying for a couple weeks to figure this out, but I'm totally stumped.
I have an array that represents item_id's: [2, 4, 5, 6, 2, 3].
I have another array that represents how many times each item shows up: [1, 1, 3, 3, 2, 5] .
I want to check that all items have been completed so I want to create an array that has the total number of item_id's in it. I will compare that array against a completed items array that will be created as the user completes each item, so, from the example above, the array I'm trying to create is:
[2, 4, 5, 5, 5, 6, 6, 6, 2, 2, 3, 3, 3, 3, 3]
EDIT:
I'm building a workout app, so a user has a workout which has many exercises. Each exercise has one or more sets associated with it. The user completes an exercise when he has completed every set for that exercise, and completes a workout when he completes all exercises for that workout. In this question I'm trying to determine when a user has finished a workout.
EDIT 2:
I wish I could award multiple right answers! Thanks everyone!
Ok, #sameera207 suggested one way, then I will suggest another way (functional style):
arr1 = [2, 4, 5, 6, 2, 3]
arr2 = [1, 1, 3, 3, 2, 5]
arr1.zip(arr2).flat_map { |n1, n2| [n1] * n2 }
item_ids = [2, 4, 5, 6, 2, 3]
counts = [1, 1, 3, 3, 2, 5]
item_ids.zip(counts).map{|item_id,count| [item_id]*count}.flatten
=> [2, 4, 5, 5, 5, 6, 6, 6, 2, 2, 3, 3, 3, 3, 3]
What's going on here? Let's look at it step by step.
zip takes two arrays and "zips" them together element-by-element. I did this to create an array of item_id, count pairs.
item_ids.zip(counts)
=> [[2, 1], [4, 1], [5, 3], [6, 3], [2, 2], [3, 5]]
map takes each element of an array and executes a block. In this case, I'm using the * operator to expand each item_id into an array of count elements.
[1]*3 => [1, 1, 1]
[[2, 1], [4, 1], [5, 3], [6, 3], [2, 2], [3, 5]].map{|item_id,count| [item_id]*count}
=> [[2], [4], [5, 5, 5], [6, 6, 6], [2, 2], [3, 3, 3, 3, 3]]
Finally, flatten takes an array of arrays and "flattens" it down into a 1-dimensional array.
[[2], [4], [5, 5, 5], [6, 6, 6], [2, 2], [3, 3, 3, 3, 3]].flatten
=> [2, 4, 5, 5, 5, 6, 6, 6, 2, 2, 3, 3, 3, 3, 3]
ids = [2, 4, 5, 6, 2, 3]
repeats = [1, 1, 3, 3, 2, 5]
result = []
ids.count.times do |j|
repeats[j].times { result << ids[j] }
end
This is a one way of doing it:
a = [2,4,5,6,2,3]
b = [1,1,3,3,2,5]
c = []
a.each.with_index do |index, i|
b[index].to_i.times {c << i }
end
p c

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