Simple way to loop through ruby on rails array - ruby-on-rails

Could someone point me in the right direction about looping through an array and extracting the required values. It's causing me issues understanding it:
array = [{"response_message"=>nil, "response_client_message"=>nil, "response_customer_message"=>nil, "closed"=>true, "updated_at"=>2012-05-30 13:20:49 UTC, "created_at"=>2012-05-30 13:20:29 UTC, "token"=>"2fda85eab962fa6e27850605f2f948ca", "price"=>"$24.00", "amount"=>#<BigDecimal:7fa3f4485428,'0.24E2',9(18)>, "currency_code"=>"USD", "metadata"=>"{\"xxx\": 5, \"xxx\": 250, \"xxx\": true, \"support\": { \"email\": true, \"phone\": false } }", "line_items"=>[{"amount"=>#<BigDecimal:7fa3f4482fe8,'0.24E2',9(18)>, "notes"=>nil, "currency_code"=>"USD", "description"=>"1 day", "price"=>"$24.00", "feature_level"=>"{\"hotspots\": 5, \"vouchers\": 250, \"customizable_logins\": true, \"support\": { \"email\": true, \"phone\": false } }", "metadata"=>"{\"hotspots\": 5, \"vouchers\": 250, \"customizable_logins\": true, \"support\": { \"email\": true, \"phone\": false } }"}]}]
One of these is generated each day, I need to loop through and present a few values. I've tried this:
array.select{|elem| elem[:updated_at]}
But that gives me a [].
How do I loop through this and extract the values?
I also need to understand how to get the line_items array out too.
Thanks

array.select{|elem| elem["updated_at"]}
pass string not a symbol

It's not entirely clear what you're after, but if you want to extract values from that array, try map:
array.map { |elem| elem["updated_at"] }
This will return you a list of all the "updated_at" values.

if you want to loop through an array and collect the updated_at values, then you should use the collect/map method.
In your example you are referencing elem[:updated_at] which is not the same as elem["updated_at"]
array.collect{|elem| elem["updated_at"]}

Related

Ruby array - comparison customer_id with an array

I have array of numbers which means governings to acces customer:
Controller :
#user_got_these_governings = current_user.governings.map{ |governing| governing.customer_id}
which_customer_is_selected = params[:user][:customer_id]
i need to compare customer_id with an array of numbers:
customer_id: 1
Governings: [7,9,6,2,3,1]
if Governings match with customer_id = true
if not = false
Something like
which_customer_is_selected = #user_got_these_governings.include?(params[:user][:customer_id].to_i)
to_i because you are probably receiving a string in the parameter and you are comparing it with an array of integers.
I think that cleanest way to do it is use in? method.
governings = [7,9,6,2,3,1]
params[:user][:customer_id].to_i.in? governings
=> true
Another possible way to do it is by using .member? method which tells whether an element is a member of the array or not.
Governings: [7,9,6,2,3,1]
Governings.member? params[:user][:customer_id].to_i
=> true

Is it possible to select certain elements without iterating through the array?

I have an array of objects, each of which has the property :cow either set to false or true:
animals = [
{
id: 1,
cow: true
},
{
id: 2,
cow: true
},
{
id: 3,
cow: true
},
{
id: 4,
cow: false
},
{
id: 5,
cow: false
}
]
I need to select all members of the array that pass a condition without iterating through every element of the array.
Is it possible?
I tried:
notCows = animals.reject { |a| !a[:cow] }
notCows = animals[0, 1, 2]
which doesn't work.
No, this is impossible. In order to find all elements that satisfy a certain condition, you need to look at all elements to see whether they satisfy that condition. It is simply logically not possible to find all elements of a collection without iterating through all elements of the collection.
You were almost there, use Enumerable#select (which scans the all the member of the collection, by the way):
animals.select { |animal| animal[:cow] }
#=> [{:id=>1, :cow=>true}, {:id=>2, :cow=>true}, {:id=>3, :cow=>true}]
Or the opposite:
animals.select { |animal| !animal[:cow] }
#=> [{:id=>4, :cow=>false}, {:id=>5, :cow=>false}]
The returned results are still Ruby objects: Arrays of Hashes.
As alternative you can group by status (Enumerable#group_by):
animals.group_by { |a| a[:cow] }
#=> {true=>[{:id=>1, :cow=>true}, {:id=>2, :cow=>true}, {:id=>3, :cow=>true}], false=>[{:id=>4, :cow=>false}, {:id=>5, :cow=>false}]}

rails array of hashes calculate one column

I have an array and it has many columns and I want to change one value of my one column.
My array is:
[
{
id: 1,
Districts: "Lakhisarai",
Area: 15.87,
Production: 67.77,
Productivity: 4271,
Year: 2015,
Area_Colour: "Red",
Production_Colour: "Orange",
Productivity_Colour: "Dark_Green",
created_at: "2018-07-24T11:24:13.000Z",
updated_at: "2018-07-24T11:24:13.000Z"
},
{
id: 29,
Districts: "Begusarai",
Area: 18.53,
Production: 29.35,
Productivity: 1584,
Year: 2015,
Area_Colour: "Red",
Production_Colour: "Red",
Productivity_Colour: "Orange",
created_at: "2018-07-24T11:24:13.000Z",
updated_at: "2018-07-24T11:24:13.000Z"
},
...
]
This is my sample array and I want my Productivity to be divided by 100 for that I am using one empty array and pushing these hashes to my array like:
j = []
b.map do |k|
if k.Productivity
u = k.Productivity/100
j.push({id: k.id, Productivity: u })
else
j.push({id: k.id, Productivity: k.Productivity })
end
Is there any simple way where I can generate this kind of array and reflect my changes to to one column. Is there any way where I don't need to push name of column one by one in push method.
I want to generate exact same array with one modification in productivity
let's say your array is e, then:
e.each { |item| item[:Productivity] = item[:Productivity]/100}
Example:
e = [{p: 12, d: 13}, {p:14, d:70}]
e.each { |item| item[:p] = item[:p]/10}
output: [{:p=>1, :d=>13}, {:p=>1, :d=>70}]
You could take help of map method here to create a new array from your original array, but with the mentioned changes.
ary.map do |elem|
h = elem.slice(:id)
h[:productivity] = elem[:Productivity] / 100 if elem[:Productivity]
h
end
=> [{:id=>1, :productivity=>42}, {:id=>29, :productivity=>15}]
Note, Hash#slice returns a new hash with only the key-value pairs for the keys passed in argument e.g. here, it returns { id: 1 } for first element.
Also, we are assigning the calculated productivity to the output only when it is set on original hash. Hence, the if condition there.

Alternate to any? which process complete array

I got a situation where I want to process whole array and perform any? operation on array to check whether some elements returns false
For example:
I want to print all truth values. And I also want to check anything is false in array:
def hel?
[true, false, true].any?{|x| p x; x}
end
The above example will print only first value (i.e) true and returns true. But I want it to print all elements of array and return false. Is there some other way to do it? or any change in same thing ? Thanks :)
To print the values, do this:
[true, false, true].each(&method(:p))
To see if all of them are truthy, do this:
[true, false, true].all?
In order to do both, do this:
[true, false, true].each(&method(:p)).all?
Or, you can put it into one iteration:
[true, false, true].inject(true){|m, n| p(n) && m}
If you want to iterate through the array you can use Enumerable#each, but it won't return a boolean:
def hel?
[true, false, true].each{|x| p x; x}
end
If you want to check all elements, you can use Enumerable#all?:
def hel?
[true, false, true].all?{|x| p x; x}
end
But in both cases you need to modify your block to get the same results.

Lua unpack bug?

I Have stumbled on a weird behavior in Lua unpack function
table1 = {true, nil, true, false, nil, true, nil}
table2 = {true, false, nil, false, nil, true, nil}
a1,b1,c1,d1,e1,f1,g1 = unpack( table1 )
print ("table1:",a1,b1,c1,d1,e1,f1,g1)
a2,b2,c2,d2,e2,f2,g2 = unpack( table2 )
print ("table2:",a2,b2,c2,d2,e2,f2,g2)
Output:
table1: true nil true false nil nil nil
table2: true false nil nil nil nil nil
The second unpack delivers parameters up to the first nil value. I could live with that.
The first table delivers 4? parameters with one being nil in the middle. It has 4 parameters that are not nil, but they aren't the one that are shown.
Could anyone explain this?
This was tried with codepad.org and lua 5.1
The problem can be resolved simply by specifying the beginning and ending indexes to unpack() and using the table.maxn() as the ending index:
table1 = {true, nil, true, false, nil, true, nil}
a1,b1,c1,d1,e1,f1,g1 = unpack( table1, 1, table.maxn(table1) )
print ("table1:",a1,b1,c1,d1,e1,f1,g1)
-->table1: true nil true false nil true nil
The true reason for the discrepancy on how the two tables are handled is in the logic of determining the length of the array portion of the table.
The luaB_unpack() function uses luaL_getn() which is defined in terms of lua_objlen() which calls luaH_getn() for tables. The luaH_getn() looks at the last position of the array, and if it is nil performs a binary search for a boundary in the table ("such that t[i] is non-nil and t[i+1] is nil"). The binary search for the end of the array is the reason that table1 is handled differently then table2.
This should only be an issue if the last entry in the array is nil.
From Programming in Lua (pg.16) (You should buy this book.):
When an array has holes--nil elements inside it--the length operator may assume any of these nil elements as the end marker. Therefore, you should avoid using the length operator on arrays that may contain holes.
The unpack() is using the length operator lua_objlen(), which "may assume any of [the] nil elements as the end" of the array.
2.2 - Values and Types
[...]
The type table implements associative
arrays, that is, arrays that can be
indexed not only with numbers, but
with any value (except nil). Tables
can be heterogeneous; that is, they
can contain values of all types
(except nil). [...]
Given nil to an entry will break the table enumeration and your variables wont be init properly.
Here is a simple example that demonstrates a problematic behavior:
table1 = {true, false, nil, false, nil, true, nil}
for k,v in ipairs(table1) do
print(k, v)
end
output:
1 true
2 false
>Exit code: 0

Resources