Is there a way to check if a hash value in Ruby is the same throughout or compare only the values for equality? - ruby-on-rails

I have the below code that returns the number of instances of an item in an array as a hash. I now need to check if the value is the same. For example if the hash is like this = {1=>3, 2=>3} i need to check if the value is the same, in this case it is but dont know how to check this.
arr.inject(Hash.new(0)) {|number,index| number[index] += 1 ;number}
Thanks

So, given h = { 1 => 3, 2 => 3 }, if I got you, you want to know if the values are ALL the same. If you knew the keys you could do
all_the_same = h[1] == h[2]
If there are more keys you want to check
all_the_same = h.values_at(1, 2, 3, 4).uniq.length == 1
If you don't know how many keys you have or which are these keys you could do
all_the_same = h.values.uniq.length == 1

Related

How exactly do I do this

In lua --
Im making a game where you need to sell items.
I have two tables. One for items,
and one for item costs.
itemcosts = {
"Chewed Gum" == 5,
"Leaf" == 2,
"Lint" == 5,
"Moldy bread crumbs" == 10
}
items = {"Leaf"}
How would I like specify the price? Like I tried
price = itemcosts[items[1]]
but It didn't work.
Any help?
Initialize your itemcosts table like this:
itemcosts = {
["Chewed Gum"] = 5,
Leaf = 2,
Lint = 5,
["Moldy bread crumbs"] = 10
}
When you want to use a table key that's a valid name in Lua, you don't need quotes or anything around it; just use it directly. When it's not a valid name, such as if it has spaces in it in your case, or even if it weren't a string at all, then you need square brackets around it. Also, remember that == is for comparison and = is for assignment.

lua - how to compare different array

im trying to compare 2 arrays but i dont know how
for example:
local array1 = { 'friend', 'work', 'privat' }
local array2 = { 'apple', 'juice', 'privat' }
if both arrays have the same value it should do a print.
i know i need to work with something like this
for x in ipairs(array1) do
if x == array2 then
print ("Hi")
end
end
but ofcourse it didnt work.
so how can i check if the array1 value contains a values from array2?
Think of it this way: You have to check each element in the first array to its counterpart in the second. If any element is not equal, you know right away that the arrays aren't equal. If every element checks out as equal, the arrays are equal.
local function arrayEqual(a1, a2)
-- Check length, or else the loop isn't valid.
if #a1 ~= #a2 then
return false
end
-- Check each element.
for i, v in ipairs(a1) do
if v ~= a2[i] then
return false
end
end
-- We've checked everything.
return true
end
how can i check if the array1 value contains a values from array2?
#luther's answer will not always work for your question..
If the arrays are different sizes, it completely fails.
If you have an array where similar element are not in the exact same index, it can return a false negative.
for example a = {'one', 'two'}; b = {'two', 'one'} will return false
Using table.sort to solve this would be a band-aid solution without fixing the real problem.
The function below will work with arrays of different sizes containing elements in any order
function array_compare(a, b)
for ia, va in ipairs(a) do
for ib, vb in ipairs(b) do
if va == vb then
print("matching:",va)
end
end
end
end
In array_compare we go through all the combinations of elements in table a and table b, compare them, and print if they are equal.
ipairs(table) uses index, value (instead of just value)
For example
local array1 = { 'friend', 'work', 'privat' }
local array2 = { 'apple', 'juice', 'privat' }
array_compare(array1, array2)
will print
matching: privat
(I'm writing a second answer to account for another possible interpretation of the question.)
If you want to see if array1 contains any value that's also in array2, you can do the following:
Convert array1 to a set. A set is a new table where the array's values become keys whose values are true.
Iterate through array2 to see if any of its values are a key in the set.
local set = {}
for _, v in ipairs(array1) do
set[v] = true
end
for _, v in ipairs(array2) do
if set[v] then
print'Hi'
-- Use a break statement if you only want to say hi once.
end
end
If the arrays are large, this algorithm should be faster than a nested loop that compares every value in array1 to every value in array2.

Remove/delete object from array in Ruby based on attribute value

I have an array
result = [{:cluster=>[0, 4], :id=>1, :units=>346, :num1=>0.161930681e7, :num2=>0.14223512616e9, "description"=>"Foo"}, { ...
And I want to take out any objects with number of units equal to 0. Looking for something similar to array.splice() but for Ruby
What is the best way to do this ?
You can use the #reject method to return the array without objects whose :units equals 0:
result.reject { |hash| hash[:units] == 0 }
There's also #reject! and #delete_if, which can be used in the same way as above but both modify the array in place.
Hope this helps!
You can achieve the same result using select method implemented on the Array class:
result.select { |el| el[:units] == 0 }

In Rails, how do I figure out if an array of objects contains specific attributes matching given values?

I'm using Ruby on Rails 5.0.1 with Ruby 2.4. I have an array of objects, stored in the array, "results." Each object has a numeric attribute
numeric_attr
I would like to know, given my array, how I can tell if I have exactly one object with a numeric attribute value of "1" and incrementing by one. Order is not important. So, for instance, if I have an array of three objects,
[MyObject(numeric_attr = 2), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]
I want to know if I have exactly one object with numeric_attr = 1, another object with numeric_attr = 2, and another with numeric_attr = 3. So the above satisfies the condition. The below example does not
[MyObject(numeric_attr = 4), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]
because although there is an object with numeric_attr = 1, there is no object with numeric_attr = 2. It is possible thet the numeric_attr field is nil. How can I figure this out?
This one-liner should work:
results.map(&:numeric_attr).sort == (1..results.count).to_a
Explanation:
results
#=> [#<MyObject:... #attr=2>, #<MyObject:... #attr=3>, #<MyObject:... #attr=1>]
results.map(&:attr)
#=> [2, 3, 1]
results.map(&:attr).sort
#=> [1, 2, 3]
(1..results.length).to_a
#=> [1, 2, 3]
# therefore:
results.map(&:attr).sort == (1..results.count).to_a
#=> true
If there is a chance that numeric_attr is nil:
results.map(&:attr).compact.sort == (1..results.count).to_a
Of course, if there is even a single nil value, the result is guaranteed to be false.
If the sequence could start at any number, not just 1:
results.map(&:attr).sort == results.count.times.to_a.
map { |i| i + results.map(&:attr).sort.first }
This is not very efficient though, as it sorts the numbers twice.
If they always start at 1 #Máté's solution works, if they can start at any arbitrary number then you could:
count = 0
array_objects.sort_by(&:numeric_attr).each_cons(2) {|a,b| count+=1 if a.numeric_attr==b.numeric_attr-1 }
count+1==array_objects.count
Not as elegant but handles a lot more situations

How to add values in nested hash in ruby's way

Here is a nested hash. We want to add all the value of "subtotal" together in ruby's way. Please be noted that the key of "0" and "1342119042142" could be any other unknown strings (number of keys is at least one. Could be more than one) when performing the addition.
{"0"=>{"lease_item_id"=>"3",
"subtotal"=>"100"},
"1342119042142"=>{"lease_item_id"=>"1",
"subtotal"=>"100",
"_destroy"=>"false"}}}
Thanks.
Like this:
set up hash:
s = {"0"=>{"lease_item_id"=>"3", "subtotal"=>"100"},
"1342119042142"=>{"lease_item_id"=>"1", "subtotal"=>"100","_destroy"=>"false"}}
calculate total:
total = s.inject(0) { |i, j| i + j.last["subtotal"].to_i}
Explanation: Look here for documentation. Basically inject is given an initial value (in the above code it is 0) and it passes the given value to the given block, where it gets set to what is returned from the block in each iteration. So in the above code, initially it is 0, on the first iteration it is set to 0 + 100 and now is equal to 100, and on the second [and final] iteration it is set to 100 + 100, 200.
Assuming h is your hash and the subtotal can be decimal value:
h.values.sum{|x| x['subtotal'].to_f}
hash = {"0"=>{"lease_item_id"=>"3", "subtotal"=>"100"}, "1342119042142"=>{"lease_item_id"=>"1", "subtotal"=>"100", "_destroy"=>"false"}}
sum = hash.values.reduce(0){|sum,inner| sum + inner["subtotal"].to_i }

Resources