rails select the bigger count/longest data from array of hashes - ruby-on-rails

i have a array of hashes like this
data = [{code: 'a', expire1: '10', stock1; '10', expire2: '11', stock2; '15'}, {code: 'b', expire1: '10', stock1; '10', expire2: '11', stock2; '15', expire3: '12', stock3; '25'}, {code: 'c', expire1: '10', stock1; '10'}]
i want to select the data with the longest/biggest count of every hash inside, so the output is must like this
{code: 'b', expire1: '10', stock1; '10', expire2: '11', stock2; '15', expire3: '12', stock3; '25'}
how can i do that ??

use Enumerable#max_by
>> data.max_by(&:length)
=> {:code=>"b", :expire1=>"10", :stock1=>"10", :expire2=>"11", :stock2=>"15", :expire3=>"12", :stock3=>"25"}

Related

jquery-query-builder Custom labels/placeholder per operator

I am trying to make a custom operator group with 5 operators: "City Is", "State Is", "Zip Code Is", "Is Within" (2 inputs, Number Of Miles From and Zip Code), "Is Beyond" (2 inputs, Number Of Miles From and Zip Code).
My issue is with labeling/placeholders for the inputs for each operator. I tried below with no luck:
operators:[
{type: 'City Is', optgroup:'Geo Location', nb_inputs: 1, multiple: false, apply_to: ['string'],placeholder: ['City']},
{type: 'State Is', optgroup:'Geo Location', nb_inputs: 1, multiple: false, apply_to: ['string'],placeholder: ['State']},
{type: 'Zip Code Is', optgroup:'Geo Location', nb_inputs: 1, multiple: false, apply_to: ['string'],placeholder: ['Zip Code']},
{type: 'Is Within', optgroup:'Geo Location', nb_inputs: 2, multiple: false, apply_to: ['string'],placeholder: ['Number of Miles From', 'Zip Code']},
{type: 'Is Beyond', optgroup:'Geo Location', nb_inputs: 2, multiple: false, apply_to: ['string'],placeholder: ['Number of Miles From', 'Zip Code']}
]
Adding placeholders to the filter in an array works, but it is starting from the first element of the array for each operator, which is causing the placeholders to not make sense. ie like below:
filters:[
{
id: 'address',
label: 'Address (geolocation)',
type: 'string',
operators: geo_operators
placeholder: ['City is','State is', 'Zip is','Number of Miles From', 'Zip Code']
}
]
Any help would be much appreciated.

How to find sum on basis of type and name key in ruby? (ruby array of hashes)

How to find a sum on basis of type and name key in ruby? (ruby array of hashes)
eatables = [{type: "fruit", name: "apple", count: 2},
{type: "vegetable", name: "pumpkin", count: 3},
{type: 'fruit', name: 'apple', count: 1},
{type: "vegetable", name: "pumpkin", count: 2}]
Desired Output
[{type: "fruit", name: "apple", count: 3},
{type: "vegetable", name: "pumpkin", count: 5}]
eatables.group_by { |h| h.slice(:name, :type) }
.map { |key, grouped| key.merge(count: grouped.sum{ |h| h[:count] }) }
The first operation splits the array into groups based on the name and type.
{{:name=>"apple", :type=>"fruit"}=>[{:type=>"fruit", :name=>"apple", :count=>2}, {:type=>"fruit", :name=>"apple", :count=>1}], {:name=>"pumpkin", :type=>"vegetable"}=>[{:type=>"vegetable", :name=>"pumpkin", :count=>3}, {:type=>"vegetable", :name=>"pumpkin", :count=>2}]}
We then map across that hash and return an array of hashes with the type, name, and sum which outputs:
=> [{:name=>"apple", :type=>"fruit", :count=>3}, {:name=>"pumpkin", :type=>"vegetable", :count=>5}]
eatables.inject(Hash.new(0)) { |h, item|
h[item.slice(:type, :name)] += item[:count]
h
}.map { |k, v|
{**k, count: v}
}
This type of problem can be solved with a reduce
output = eatables.reduce({}) do |hsh, current|
if hsh.has_key?(current[:type]+current[:name])
hsh[current[:type]+current[:name]][:count] += current[:count]
else
hsh[current[:type]+current[:name]] = current
end
hsh
end.values

Is there any method similar to in_groups_of in rails but for hash?

I want to split this hash in groups of size number, let's just say 2 items per group
hash = {'mail1#email.com': {name: 'name 1'},
'mail2#email.com': {name: 'name 2'},
'mail3#email.com': {name: 'name 3'},
'mail4#email.com': {name: 'name 4'},
'mail5#email.com': {name: 'name 5'}
}
wanted result should be:
hash1 = {'mail1#email.com': {name: 'name 1'},
'mail2#email.com': {name: 'name 2'}}
hash2 = {'mail3#email.com': {name: 'name 3'},
'mail4#email.com': {name: 'name 4'}}
hash3 = {'mail5#email.com': {name: 'name 5'}}
You can use Enumerable#each_slice, after that map each element as a hash with Array#to_h:
hash1, hash2, hash3 = hash.each_slice(2).map(&:to_h)
p hash1 # {:"mail1#email.com"=>{:name=>"name 1"}, :"mail2#email.com"=>{:name=>"name 2"}}
p hash2 # {:"mail3#email.com"=>{:name=>"name 3"}, :"mail4#email.com"=>{:name=>"name 4"}}
p hash3 # {:"mail5#email.com"=>{:name=>"name 5"}}

RSpec Expect Hash to include an Array of key value pairs

Still learning Rspec as a whole, so thanks for patience.
Return value is this:
{ supermodel: {
'id': 1,
'name': 'J',
'model_attributes': [
{attr1: 'T', attrA: 1},
{attr2: 'F', attrB: 2},
{attr3: 'T', attrC: 3}
],
}
}
Trying to get an expectation that says that a hash key named 'model_attributes' contains a value of an array that includes the following key value pairs - {attr2:F, attrB: 2} and {attr3: T, attrC: 3}.
Any insight would be welcome.
describe 'Stuff' do
let(:model_attributes) do
[
{attr1: 'T', attrA: 1},
{attr2: 'F', attrB: 2},
{attr3: 'T', attrC: 3}
]
end
let(:result) do
{ supermodel:
{
'id': 1,
'name': 'J',
'model_attributes': model_attributes
}
}
end
it 'has the correct model_attributes value' do
expect(result.dig(:supermodel, :model_attributes)).to eq(model_attributes)
end
end
Try
describe 'ModelAttributes' do
let(:model_attributes) { [{ attr1: 'T', attrA: 1 },
{ attr2: 'F', attrB: 2 },
{ attr3: 'T', attrC: 3 }] }
it 'includes the required attributes' do
expect(model_attributes).to include({ attr2:'F', attrB: 2 }, { attr3: 'T', attrC: 3 })
end
end
In retrospect this is alot easier now. Simply traversing the hash and expecting the values was the easiest way. Refactoring ended me up in doing this:
supermodel[:model_attributes].each do |attr|
expect(attr[:attrB])to be 2
end
Thanks for all the suggestions, led me down the right path.

Ransack: how to join table multiple times with different alias?

Suppose I have :items with a has_many association with :properties, then I can search for all items that have a property with name 'a_name' and value 'a_value' like this
q: { properties_name_eq: 'a_name', properties_value_eq: 'a_value' }
Now what if I want to search for all items that have a property with name 'a_name' and value 'a_value' and also a property with name 'another_name' and value 'another_value'?
The following doesn't work as it joins the properties table only once
q: {
g: {
'0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' },
'1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'}
}
}
The generated SQL looks something like this
SELECT DISTINCT "items".* FROM "items"
LEFT OUTER JOIN "properties" ON "properties"."item_id" = "items"."id"
INNER JOIN ((SELECT "items".* FROM "items")) AS sel_111 on sel_111.id
WHERE
(("properties"."name" = 'a_name' AND "properties"."value" = 'a_value') AND ("properties"."name" = 'another_name' AND "properties"."value" = 'another_value'))
EDIT:
To make it more clear what I am after, I'll paste a spec below.
Item.create name: 'ab', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'b1'}]
Item.create name: 'a', properties_attributes: [{ name: 'a', value: 'a1'}]
Item.create name: 'b', properties_attributes: [{name: 'b', value: 'b1'}]
Item.create name: 'ax', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'x'}]
Item.create name: 'bx', properties_attributes: [{ name: 'a', value: 'x'}, {name: 'b', value: 'b1'}]
Item.create name: 'other', properties_attributes: [{ name: 'other', value: '123'}]
get :index, q: { properties_name_eq: 'a', properties_value_eq: 'a1' }
names = JSON.parse(response.body).map{|u| u['name']}
expect(names).to match_array ['ab', 'a', 'ax'] # OK!
get :index,
q: {
m: 'or',
g: {
'0' => { properties_name_eq: 'a', properties_value_eq: 'a1' },
'1' => { properties_name_eq: 'b', properties_value_eq: 'b1'}
}
}
names = JSON.parse(response.body).map{|u| u['name']}
expect(names).to match_array ['ab'] #FAILS!
Just use Model.search(params[:q].try(:merge, m: 'or')), using your example:
q: {
m: 'or',
g: {
'0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' },
'1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'}
}
}
You can find more information here
You need an or at the where level of your query, because properties.name can't be equal 'a_name' and 'another_name' at the same time. A second alias for the table is not required.
You can solve this by using multiple queries.
For each name + value property, get all item IDs with this property
Intersect the resulting IDs for each property into item_ids
In the final query on :items, add the clause WHERE id IN (item_ids)
Here's a code example that does steps 1 & 2:
def property_item_ids(conditions)
conditions.inject([]) do |result, (key, condition)|
result.method(result.empty? ? '+' : '&').(Property.ransack(m: "and", g: condition).pluck(:item_id).to_a)
end
end
Get the item IDs that have all properties:
conditions = {
'0' => { properties_name_eq: 'a', properties_value_eq: 'a1' },
'1' => { properties_name_eq: 'b', properties_value_eq: 'b1'}
}
item_ids = property_item_ids(conditions)
For step 3, invoke ransack with item_ids:
q: {
m: 'and',
g: {
'0' => { item_id_in: item_ids }
}
}

Resources