otherCount = #products.drop(3).inject(0) { |sum,count| sum, count }
My Ruby environment is 1.9.3.
products is an array of hashes elements. It has properties: productName and count. I want to sum up the count values of all the hashes in the products array (with the exception of the first 3 hashes). Documentation I've found are either too brief in their explanation or use a different Ruby environment, which may likely be the problem. The code I wrote is written as per this document.
I drop the first 3 elements, then call inject, with an initial value of 0, carry over variable called sum, and count is the name of the field in each of the hashes whose value I want to add up.
Change
inject(0) { |sum,count| sum, count }
to
inject(0) { |sum,p| sum + p['count'] }
Isolate the code
If you're having trouble integrating this, copy and paste these 2 lines into an irb session to verify this works:
a = [{'count' => 1},{'count' => 2},{'count' => 3}]
a.inject(0) { |sum,p| sum + p['count'] }
# => 6
Hopefully this helps bridge the gap.
Related
I've got a collection of complex documents.
{
<some fields>,
meta_info: {
company_name: String,
invalid: Boolean,
mobile_layout: String,
<more fields>
}
<lots more fields>
}
I ask Rails to find me all those documents where meta_info.invalid is true/false/nil using
finished_acts.where('meta_info.invalid' => true/false/nil)
Now there is ONE document where the field does not exist. I ask...
finished_acts.find('meta_info.invalid' => {'$exists' => false})
=> nil
which is simply untrue (plus it also yields nil if I ask {'$exists' => true}), and so is
finished_acts.where('meta_info.invalid' => {'$exists' => false}).count
=> 0
How can I find this document? I've spent days with a collection of statistical data which was always off by one count when compared to the info given me by the database itself, and this nonexistent field was the reason.
I am using mongoDB V3.4.17 and Mongoid 6.1.0.
EDIT: I've since learned that I used the .find command incorrectly, it is only intended to be used for the _id field and does not accept JSON/Hashes.
My problem obviously shows a bug in the implementation of the Active Record adaptation of Mongoid, and I am slowly converting my code to always use aggregations. When doing so, I get the correct number of documents. Of course, the structure returned by aggregations is more complex to handle since it is only hashes and arrays, but if that's the trade-off for getting correct results I am happy with it.
Don't rely on the ActiveRecord adaptation in Mongoid; use the aggregation pipeline. This will (to the best of my knowledge) always return correct results since it simply pushes the argument hash into mongo.
The aggregation pipeline at first seems unintuitive to use, but after you get to know how to use it it is a very powerful tool if you want to make complex queries. The Rails syntax is as follows:
MyClassName.collection.aggregate( <array> )
where the <array> contains hashes, each of which is a command used on the result of the execution of the preceding hash. The documentation can be found at https://docs.mongodb.com/manual/aggregation/.
To convert the commands there to Ruby it is only required to surround the entries by quotes.
To give an example: The following is the mongo syntax:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
This takes all documents from the orders collection and selects all those where the status field matches "A" (the word $match left of the colon is a mongo command). Those then get grouped ($group) by the cust_id field and the sum ($sum) of the contents of the amount field is computed.
If you want to convert this to Ruby, you change it into
Orders.collection.aggregate([
{ '$match': {'status': 'A'}},
{ '$group': {'_id': '$cust_id', 'total': {'$sum': '$amount'}}}
])
This worked for me, and what's even better is that it takes significantly less time than using Orders.where(...) in Rails and doing the computation in Rails.
The trade-off is that you don't get returned Ruby objects but hashes of arrays of hashes.
I have a key => value table I'd like to sort in Lua. The keys are all integers, but aren't consecutive (and have meaning). Lua's only sort function appears to be table.sort, which treats tables as simple arrays, discarding the original keys and their association with particular items. Instead, I'd essentially like to be able to use PHP's asort() function.
What I have:
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
What I want after the sort operation:
items = {
[1234] = "bar",
[3188] = "baz",
[1004] = "foo",
[7007] = "quux",
}
Any ideas?
Edit: Based on answers, I'm going to assume that it's simply an odd quirk of the particular embedded Lua interpreter I'm working with, but in all of my tests, pairs() always returns table items in the order in which they were added to the table. (i.e. the two above declarations would iterate differently).
Unfortunately, because that isn't normal behavior, it looks like I can't get what I need; Lua doesn't have the necessary tools built-in (of course) and the embedded environment is too limited for me to work around it.
Still, thanks for your help, all!
You seem to misunderstand something. What you have here is a associative array. Associative arrays have no explicit order on them, e.g. it's only the internal representation (usually sorted) that orders them.
In short -- in Lua, both of the arrays you posted are the same.
What you would want instead, is such a representation:
items = {
{1004, "foo"},
{1234, "bar"},
{3188, "baz"},
{7007, "quux"},
}
While you can't get them by index now (they are indexed 1, 2, 3, 4, but you can create another index array), you can sort them using table.sort.
A sorting function would be then:
function compare(a,b)
return a[1] < b[1]
end
table.sort(items, compare)
As Komel said, you're dealing with associative arrays, which have no guaranteed ordering.
If you want key ordering based on its associated value while also preserving associative array functionality, you can do something like this:
function getKeysSortedByValue(tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
local sortedKeys = getKeysSortedByValue(items, function(a, b) return a < b end)
sortedKeys is {1234,3188,1004,7007}, and you can access your data like so:
for _, key in ipairs(sortedKeys) do
print(key, items[key])
end
result:
1234 bar
3188 baz
1004 foo
7007 quux
hmm, missed the part about not being able to control the iteration. there
But in lua there is usually always a way.
http://lua-users.org/wiki/OrderedAssociativeTable
Thats a start. Now you would need to replace the pairs() that the library uses. That could be a simples as pairs=my_pairs. You could then use the solution in the link above
PHP arrays are different from Lua tables.
A PHP array may have an ordered list of key-value pairs.
A Lua table always contains an unordered set of key-value pairs.
A Lua table acts as an array when a programmer chooses to use integers 1, 2, 3, ... as keys. The language syntax and standard library functions, like table.sort offer special support for tables with consecutive-integer keys.
So, if you want to emulate a PHP array, you'll have to represent it using list of key-value pairs, which is really a table of tables, but it's more helpful to think of it as a list of key-value pairs. Pass a custom "less-than" function to table.sort and you'll be all set.
N.B. Lua allows you to mix consecutive-integer keys with any other kinds of keys in the same table—and the representation is efficient. I use this feature sometimes, usually to tag an array with a few pieces of metadata.
Coming to this a few months later, with the same query. The recommended answer seemed to pinpoint the gap between what was required and how this looks in LUA, but it didn't get me what I was after exactly :- which was a Hash sorted by Key.
The first three functions on this page DID however : http://lua-users.org/wiki/SortedIteration
I did a brief bit of Lua coding a couple of years ago but I'm no longer fluent in it.
When faced with a similar problem, I copied my array to another array with keys and values reversed, then used sort on the new array.
I wasn't aware of a possibility to sort the array using the method Kornel Kisielewicz recommends.
The proposed compare function works but only if the values in the first column are unique.
Here is a bit enhanced compare function to ensure, if the values of a actual column equals, it takes values from next column to evaluate...
With {1234, "baam"} < {1234, "bar"} to be true the items the array containing "baam" will be inserted before the array containing the "bar".
local items = {
{1004, "foo"},
{1234, "bar"},
{1234, "baam"},
{3188, "baz"},
{7007, "quux"},
}
local function compare(a, b)
for inx = 1, #a do
-- print("A " .. inx .. " " .. a[inx])
-- print("B " .. inx .. " " .. b[inx])
if a[inx] == b[inx] and a[inx + 1] < b[inx + 1] then
return true
elseif a[inx] ~= b[inx] and a[inx] < b[inx] == true then
return true
else
return false
end
end
return false
end
table.sort(items,compare)
I am building a shopping cart app in rails. CartItems model has a column for quantity of the type integer and a column for cart_price of the type decimal. For each item added to the cart a new row is added to the database
Model name CartItems. The controller retrieves quantity and price successfully. But when multiplying I receive the error message above. Once the multiplication works I want to add the products together to get the subtotal for the cart.
def subtotal
#cart_content = #cart_item.pluck(:quantity,:cart_price)
#subtotal = #cart_content.inject(:*)
end
When I remove .inject(:*) from #subtotal the controller retrieves the correct data.
Example output from view for two products, with quantity and price value present
[[3, #BigDecimal:7fc9a9b2d980,'0.1285E3',18(36)>], [1, # BigDecimal:7fc9a9b2d7c8,'0.115E3',9(27)>]]
I'm not 100% sure but what you probably wanted to achieve is:
#cart_content.sum { |c| c.inject(:*) } - single reduce won't work because it expects a number not an array
You are probably better of adding a column to the model that already contains the value of quantity * cart_price # name it row_total
Then you can easily sum the new column like this:
ModelName.sum(:row_total)
You seem to be trying to multiplying the individual elements, which ruby does not like as they are arrays themselves.
As djaszczurowski suggested, I'd recommend summing over the array after multiplying the elements.
Extending on his answer, I'd suggest to replace the inject with the following, as in (at least for me) it is more descriptive of what (I think) you want to do with the code:
#subtotal = #cart_content.sum { |count, price| count * price }
I am working with Ruby 2.0.0 and Rails 4.0.9, on Oracle 11g database.
I query the database to get pairs of values [date, score] to draw a chart.
Unfortunately, my query returns triplets such as [date, score, something], and the chart fails.
Here is the query:
#business_process_history = DmMeasure.where("period_id between ? and ? and ODQ_object_id = ?",
first_period_id, current_period_id, "BP-#{#business_process.id}").
select("period_day, score").order("period_id")
Here is the result in the console:
DmMeasure Load (1.2ms) SELECT period_day, score FROM "DM_MEASURES" WHERE (period_id between 1684 and 1694 and ODQ_object_id = 'BP-147') ORDER BY period_id
=> #<ActiveRecord::Relation [#<DmMeasure period_day: "20140811", score: #<BigDecimal:54fabf0,'0.997E2',18(45)>>,
#<DmMeasure period_day: "20140812", score: #<BigDecimal:54fa7e0,'0.997E2',18(45)>>, ...]
Trying to format the result also returns triplets:
#business_process_history.map { |bp| [bp.period_day, bp.score] }
=> [["20140811", #<BigDecimal:54fabf0,'0.997E2',18(45)>],
["20140812", #<BigDecimal:54fa7e0,'0.997E2',18(45)>], ...]
Where does this come from?
How can I avoid this behaviour?
Thanks for your help,
Best regards,
Fred
what triplets? From what I can see, you have two attributes per item: 'period_day' (a string representing a date) and 'score' (a BigDecimal representation of a single number).
The ruby BigDecimal is just one way of representing a number.
eg if you play around with them in the rails console:
> BigDecimal.new(1234)
=> #<BigDecimal:f40c6d0,'0.1234E4',9(36)>
The first part, as you can see, a bit like scientific notation, it contains the significant digits and precision.
To figure out what the 18(45) is, I had to dig into the original c-code for the BigDecimal#inspect method.
Here's the commenting for that method:
/* Returns debugging information about the value as a string of comma-separated
* values in angle brackets with a leading #:
*
* BigDecimal.new("1234.5678").inspect ->
* "#<BigDecimal:b7ea1130,'0.12345678E4',8(12)>"
*
* The first part is the address, the second is the value as a string, and
* the final part ss(mm) is the current number of significant digits and the
* maximum number of significant digits, respectively.
*/
The answer being: the current number of significant digits and the maximum number of significant digits, respectively
I have a hash variable that contains the results from an ActiveRecord search, which will be iterated through to display data. My code (transcribed) goes somewhere like this:
hvar=User.map{|x| {:name => x.name, :type => x.type, :section => x.section,
:result => (x.var1/x.var2).round(1)}}
The hash variable 'hvar' would then display the following through an .inspect :
[
{:name=>'Michael', :type=>7, :section=>1, :result=>4.1},
{:name=>'Seymour', :type=>4, :section=>1, :result=>3.9},
{:name=>'Walter', :type=>2, :section=>1, :result=>6.3},
{:name=>'Josephine', :type=>7, :section=>1, :result=>5.4},
{:name=>'Carla', :type=>7, :section=>0, :result=>5.4}
]
So far, so good.
Now, I wish to do a search through that resulting hash, e.g. all those records of type 7, and I'm not sure how to get to it. I found that you could do something like this:
mission=hvar.select{|k| k[:type] == 7}
But it gives me 0 results, which makes sense to me, as I think it is searching through the "first level" of the hash (i.e. 0, 1, 2, 3) instead of the subhashes within.
How could I find all those records with type 7? And to that effect, how could I also do a search on two fields? Say, type == 7 and section == 1.
In case you're wondering, I'm not doing the search from the ActiveRecord itself, cause I have to iterate through every single record and arrange them in a pivoted table that merges this data with another table. So, to make it more efficient I figured to use a hash instead of iterating through the ActiveRecord, which currently it's spitting somewhere around 1700 SQL queries.
Thanks in advance.
Your code is written correctly. The only thing that can really be answered is
how could I also do a search on two fields? Say, type == 7 and section == 1.
The same way you're doing so now, plus an additional condition:
mission = hvar.select { |k| k[:type] == 7 && k[:section] == 1}