Duplicate Records created from Association - ruby-on-rails

I am using Mongoid, Rails and Fabrications and at a total loss with how this is happening. Any thoughts very appreciated, but I know this pretty complicated. I just want to fabricate a user and have only four joined groups, but I keep getting eight loaded.
Here is the relevant section of my code
#user1 = Fabricate.build(:registered)
#user1.joined_groups << [common_group,
cali_group,
ca46,
Fabricate(:polco_group, {:name => "Gang of 13", :type => :custom})]
When I run #user1.joined_groups.size I get 4, but when I do #user1.joined_groups.map(&:name), I get 8 records:
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
(where i have replaced all BSON::ObjectId('4eab3ca5f11aac2701000009') statements with ones and removed a lot of the middle code.
The full set of code is available here: https://gist.github.com/1323984
Most bizzarre simply calling map might be causing the problem.
puts "just created user with these groups:"
puts #user1.joined_groups.map(&:name)
puts "then secondly"
puts #user1.joined_groups.map(&:name)
Generates this (!):
just created user with these groups:
Dan Cole
CA
CA46
Gang of 13
then secondly
Dan Cole
CA
CA46
Gang of 13
Dan Cole
CA
CA46
Gang of 13
Thanks for any insight! After repeated attempts, I can't figure out a way in terminal to duplicate this, so I am suspecting the Fabrication gem. (Update: nope, I get this error with standard mongoid objects, so I am totally blaming mongoid.)
Tim

I think the problem might simply be that you are not pushing the groups onto the user correctly. Try using concat or separately shoveling them.
#user1.joined_groups.concat([common_group,
cali_group,
ca46,
Fabricate(:polco_group, {:name => "Gang of 13", :type => :custom})])

Related

Normalizing data that has low variation

I ran several benchmarks on a CPU cache simulation to count the number of the reuse distances (the distance between two accesses of the same cache entry during execution of the program), here are two examples of the data I got from two different benchmarks:
Benchmark 1:
"reuse_dist_counts": {
"-1": 340,
"0": 623,
"1": 930,
"100": 1,
"107": 1,
"114": 1,
"121": 1,
"128": 1,
"135": 1,
"142": 1,
"149": 1,
"156": 1,
"163": 1,
"170": 1,
"177": 1,
"184": 1,
"191": 1,
"198": 1,
"2": 617,
"205": 1,
"212": 1,
"219": 1,
"226": 1,
"233": 1,
"240": 1,
"247": 1,
"254": 1,
"261": 1,
"268": 1,
"275": 1,
"282": 1,
"289": 1,
"296": 1,
"3": 617,
"303": 1,
"310": 1,
"311": 1,
"314": 1,
"4": 1,
"48": 1,
"55": 1,
"62": 1,
"69": 1,
"76": 1,
"79": 1,
"86": 1,
"93": 1
}
Benchmark2:
"reuse_dist_counts": {
"-1": 58,
"0": 128,
"1": 320,
"11": 17,
"12": 1,
"13": 2,
"14": 4,
"15": 18,
"16": 14,
"17": 13,
"18": 13,
"19": 16,
"2": 256,
"20": 16,
"21": 17,
"22": 17,
"23": 2,
"24": 1,
"25": 3,
"26": 3,
"27": 2,
"28": 3,
"29": 2,
"3": 289,
"30": 2,
"31": 2,
"34": 2,
"35": 6,
"38": 2,
"39": 2,
"4": 198,
"40": 4,
"41": 1,
"43": 1,
"44": 2,
"45": 1,
"47": 1,
"48": 2,
"5": 63,
"50": 1,
"6": 81,
"7": 106,
"8": 1
}
it has the form a:b where a is a reuse distance and b is how many times that reuse distance has been found during the execution.
As I'm going to design a neural network based on this data, it's necessary to find a good normalization to represent it in a different way. Any idea on how to normalize such data with such low variations, and how to represent its features vectors?

How to get the sum of this ActiveRecord::Associations::CollectionProxy?

[#<ActiveRecord::Associations::CollectionProxy [#<InvoiceServiceType id: 1, value_charged: 50.0, invoice_id: 4, service_type_id: 1>, #<InvoiceServiceType id: 2, value_charged: 50.4, invoice_id: 4, service_type_id: 2>]>, #<ActiveRecord::Associations::CollectionProxy [#<InvoiceServiceType id: 8, value_charged: 70.0, invoice_id: 1, service_type_id: 2>, #<InvoiceServiceType id: 9, value_charged: 50.0, invoice_id: 1, service_type_id: 6>]>]
I want to sum all value_charged .
im try map(&:value_charged).sum
collect..
and nothing :(
Thank you
Lets say that you have a #object with a has_many relationship details, and details have a field call :value_charged, you could try sum all the :value_charged of #object.details with:
#object.details.sum(:value_charged)

Cycle through an array in Ruby

I have an array of the form [1,2,3,4,5].
Is it possible to loop through this array and during each iteration get an array where the starting point is the current element and the end point is the element before that?
Like
[1,2,3,4,5]
[2,3,4,5,1]
[3,4,5,1,2]
[4,5,1,2,3]
[5,1,2,3,4]
I am trying with .cycle method of array but it is not giving the expected result.
Check out rotate.
a = [ "a", "b", "c", "d" ]
a.rotate #=> ["b", "c", "d", "a"]
irb(main):005:0> array = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):006:0> array.size.times.map{|i| array.rotate(i)}
=> [[1, 2, 3, 4, 5], [2, 3, 4, 5, 1], [3, 4, 5, 1, 2], [4, 5, 1, 2, 3], [5, 1, 2 , 3, 4]]

Postgree double group by repeating attribute

I have table with some columns: id, user_id, message_id, message_type; for example:
id: 1, user_id: 1, message_id: 4, message_type: 'Warning'
id: 2, user_id: 1, message_id: 5, message_type: 'Warning'
id: 3, user_id: 1, message_id: 6, message_type: 'Warning'
id: 4, user_id: 2, message_id: 4, message_type: 'Error'
id: 5, user_id: 2, message_id: 1, message_type: 'Exception'
id: 6, user_id: 1, message_id: 2, message_type: 'Exception'
id: 7, user_id: 1, message_id: 3, message_type: 'Exception'
id: 8, user_id: 2, message_id: 4, message_type: 'Exception'
I want to get grouping result like news in social networks. On columns user_id and message_type, while message_type repeating. And need LIMIT 20 ORDER BY id DESC.
Example:
id: 8, user_id: 2, message_id: 4, message_type: 'Exception'
id: {6,7} user_id: 1, message_id: {2,3}, message_type: 'Exception'
id: 5, user_id: 2, message_id: 1, message_type: 'Exception'
id: 4, user_id: 2, message_id: 4, message_type: 'Error'
id: {1, 2, 3}, user_id: 1, message_id: {4, 5, 6}, message_type: 'Warning'
How to do it with best performance?
I found only 1 way:
With window function lead() find a moment when was changed dict (user, message type)
With window function sum() set sequnce number for each new dict
Group by sequence and select what you need:
Checking:
create table test (
id serial primary key,
user_id integer,
message_id integer,
message_type varchar
);
insert into test (user_id, message_id, message_type)
values
(1, 4, 'Warning'),
(1, 5, 'Warning'),
(1, 6, 'Warning'),
(2, 4, 'Error'),
(2, 1, 'Exception'),
(1, 2, 'Exception'),
(1, 3, 'Exception'),
(2, 4, 'Exception')
;
select
array_agg(grouped.id) as record_ids,
grouped.user_id,
array_agg(grouped.message_id) as message_ids,
grouped.message_type
from (
select changed.*,
sum(changed.changed) over (order by changed.id desc) as group_n
from (
select tt.*,
case when lag((user_id, message_type)) over (order by tt.id desc) is distinct from (user_id, message_type) then 1 else 0 end as changed
from test tt
) changed
order by id desc
) grouped
group by grouped.group_n, grouped.user_id, grouped.message_type
order by grouped.group_n
;
Result:
record_ids | user_id | message_ids | message_type
------------+---------+-------------+--------------
{8} | 2 | {4} | Exception
{7,6} | 1 | {3,2} | Exception
{5} | 2 | {1} | Exception
{4} | 2 | {4} | Error
{3,2,1} | 1 | {6,5,4} | Warning
(5 rows)
The array_agg function should do the trick:
SELECT user_id,
message_type,
ARRAY_AGG (DISTINCT id),
ARRAY_AGG (DISTINCT message_id)
FROM mytable
GROUP BY user_id, message_type

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

Resources