Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I need to sum values in an array hashes and I found a way to do it here
but it sure seems like there should be a more elegant way in Ruby.
Here is what works;
sales = [{"sale_price"=>210000, "deed_type"=>"Warranty Deed"}, {"sale_price"=>268300, "deed_type"=>"Warranty Deed Joint"}]
total_sales = sales.inject(0) {|sum, hash| sum + hash["sale_price"]}
The totals line is not very readable. It would be nice if something like this worked;
total_sales = sales.sum("sale_price")
Is this just wishful thinking or am I overlooking a better solution?
I like using the map/reduce metaphor like so:
total_sales = sales.map {|s| s['sale_price']}.reduce(0, :+)
The reduce method is a synonym for the inject method, I find the name inject to be somewhat confusing with the memo component. It has another form I use above to take the initial value and a reference to a method call used for the combination/reduction process.
I think the overall pattern of mapping the values and then reducing them to an aggregate is well known and self-documenting.
EDIT: Use symbol :+ instead of proc reference &:+
You can make it work:
sales = [{"sale_price"=>210000, "deed_type"=>"Warranty Deed"}, {"sale_price"=>268300, "deed_type"=>"Warranty Deed Joint"}]
def sales.sum(by)
inject(0){|sum, h| sum + h[by]}
end
p sales.sum("sale_price") #=> 478300
Note this sum method (sum_by might be a better name) is not defined on Array, but only on the specific sales array.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am working on ruby on rails project and I want to match specific substring with string suppose part1_hello_part2,part3_hii_part4 this is 2 strings and I want to match with the substring _hello_
Items array:
[
{
id:1,
name:part1_hello_part2,
},{
id:2,
name:part3_hii_part4,
}
...
...
{
}
]
for item in #items
if item.name.to_s.match? /\b.*?_hello_.*?\b/
#data.push item
end
end
In the loop of items, I have strings with the name field if match with a specific substring then item push in the data variable. how can I do this?
Update: Actually I want to push the matched data(*_hello_*) in new array #data so I use that in another process
It's not clear what #items is. If it's an ActiveRecord::Relation, then you probably just want to use a query. If it's some other enumerable, like an Array...
item in #items isn't very rubyish, so you might consider:
#items.each do |item|
if item.name.to_s.match? /\b.*?_hello_.*?\b/
#data.push item
end
end
But, #data.push suggests you're building an array, so you might consider:
#data = #items.each_with_object([]) do |item, to_return|
if item.name.to_s.match? /\b.*?_hello_.*?\b/
to_return.push item
end
end
But, each_with_object is a long walk when you have select, so you might consider:
#data = #items.select do |item|
item.name.to_s.match? /\b.*?_hello_.*?\b/
end
Now, you also have include?, so you might consider:
#data = #items.select do |item|
item.name.to_s.include?('_hello_')
end
At that point, you might want to get it all onto one line, so you might consider:
#data = #items.select { |item| item.name.to_s.include?('_hello_')}
You might want to compact that a little more, so you might consider:
#data = #items.select { |item| item.name.to_s['_hello_'] }
As you have probably tried out already by yourself using irb,
'part1_hello_part2'.match? /\b.*?_hello_.*?\b/
returns true, so the problem is not the matching part (although you probably should have written it better as .include?('_hello_'), which looks - at least to me - simpler and easier to understand than your obscure regexp.
If the matching does not work, it means that the left side is not the string what you expect it to be. At the very least, you should output item.name.to_s for debugging purposes. You did not show what #items is. You only said that it is an Array and show a printed representation of its content, which is not the same as showing what the content really is. From the display, it looks like the array elements were hashes, but in this case, I would expect that the elements were accessed by item[:name]. But if ìtemis not just a Hash, but an object which understands the name` method, this is, of course, a correct usage.
Aside from this, and assuming that #data understands the method push, your code looks fine, and you need to ask more precisely, which of the statements you have posted, does not yield the expected outcome.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Trying to add the contents of an array together.
["75.00", "50.00", "25.00"] the way I'm getting that info is with
c = Credit.last
c.payments.map(&:payment_amount).to_a
I'm trying to add up all the values together in the array.
The other posters are correct in that your question doesn't conform to the how to ask guidelines. The responses are not intended to put you down but rather to maintain the quality of content for stack overflow. That said this should get you where you need to go. IN the future please read the guidelines and submit accordingly.
Credit.last.payments.sum(:payment_amount.to_f)
One thing you may not have considered is that the array ["75.00", "50.00", "25.00"] contains a bunch of strings.
If you were to sum them together like this:
["75.00", "50.00", "25.00"].sum
# or like this as one commenter suggested
["75.00", "50.00", "25.00"].reduce(&:+)
# or the long-handed version
["75.00", "50.00", "25.00"].reduce {|str, val| str + val }
You would actually get "75.0050.0025.00". This is because the individual strings in the array are getting concatenated together.
So in fact, you would need to convert the array to floats or integers first. This can be done like this:
floats = ["75.00", "50.00", "25.00"].collect(&:to_f)
# or the long-handed version
["75.00", "50.00", "25.00"].collect {|val| val.to_f }
Then you can sum the values:
sum = floats.sum
Edit:
I just tried summing a string column via ActiveRecord and got an exception ActiveRecord::StatementInvalid: TinyTds::Error: Operand data type nvarchar is invalid for sum operator.:.
payment_total = Credit.last.payments.sum(:payment_amount)
# returns ActiveRecord::StatementInvalid:
# TinyTds::Error: Operand data type nvarchar is invalid for sum
# operator.
Looks like that won't be an option for you. Although, you could change the datatype of the column so that it is something other than a string. If you change the column datatype then you will be able to use aggregate functions.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Any tips to refactor this condition?
params = {:p1=>"foo", :p2=>true, :p3=>nil, :pN=>""}
if params[:p1].present? && params[:p2].present? && params[:pN].present?
# do something...
Something like this:
params.values_at(:p1, :p2, :pN).all?(&:present?)
if params.values_at(*%i[p1 p2 p3]).all?(&:present?)
values_at returns an Array of the values for each key you provide.
all? is true iff the predicate (present?) is true for every member of the enumerable. values_at will include nil for a missing key (rather than omit it), so you don't need to worry about the array collapsing down to only present values.
keys = [:p1, :p2, :pN]
puts "hi" if keys.all? { |k| params[k].present? }
This has the advantage of terminating the hash lookup as soon as params[k].present? is false.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I've got a pretty standard Preferences table. I'd like to list all true booleans for each record therein. How would I go about that? I know that Preference.column_names will give me all, but I need each record's particular true settings. Any idea? Something like
#preference.column_names do |c|
c if c = true
end
Thanks!
Here's the general idea of looping through an objects attributes with the attribute name and value. Are you having to filter out only boolean fields? Or are all the fields boolean?
#preference.attributes.each do |attr_name, attr_value|
"#{attr_name} is #{attr_value}" if attr_value == true
end
First you'll need to know the boolean columns, something like this should give you their names:
booleans = Model.columns.select { |c| c.type == :boolean }.map(&:name)
Then you can use send to extract the values based on a name and a simple "is it true" test takes care of the rest:
trues = booleans.select { |name| #preference.send(name) == true }
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have two questions.
1) I need to create a dynamic structure, whose members are driven through an array.
For ex:
members = [:a, :b]
Config = Struct.new(members) #=> Struct.new(:a, :b)
FlatConfig = Struct.new(members) #=> Struct.new(:a, :b)
config = Config.new()
flat = FlatConfig.new()
After some days, If I need to add another member to these struct, then all I need to do is add a member in that members array (memebers = [:a, :b, :c]) and I don't need to tough the code further. Thus I am asking this. How to achieve this?
2) Now I need to build the values of flat Struct members by means of doing some manipulation on config struct member values.
For eg:
config.each{|configMember|
result = configMember.collect{|c| someArray.collect{|s| s + '--' + y}}
flat[":#{cofigMember}"] = result #=> Intent is to store result in same member as iterated through config struct.
}
How to achieve (1) and (2)?
Thanks in advance.
For your 1), use the splat operator:
Struct.new(*members)
I don't really understand your second question. Is "how can I access the same variable in two configs"?
config.members.each { |key|
configMember = config[key]
# do something
flat[key] = result
}