Condition as a parameter of a method in ruby - ruby

I am working with a class that is a collection rows containing data. I created a method
range#selection!(field, condition)
to reduce the contained rows that do not match the condition.
For a while it was enough to provide a regex as condition to eliminate all rows where a field had values not fitting to regex...
Now I would need to compare field values in a mathematical sense <=, >= , more worse I would need to filter fields that contain a date later than a specified date...
def selection!(field) {value<=3}
value = 4
if yield then
...
end
This is obviously not working but it is what I would somehow need... passing only a condition that I can earliest evaluate when "value" has a vale inside the method. but avoiding to move all the [...] in a block tht I rwrite over and over again
ideas?
Marc

What if you pass a block to your method and in your method you use select/reject_if with that block to filter out your collection?

Related

CountIFS with filter

Syntax:
CountIfS(Range1, condition1, Range2, Condition2,.... So on)
Can we use FILTER function to retrieve a value.
I am trying below function
=COUNTIFS(A2:A610, "Yes", $B$2:$B$610, FILTER(Sheet2!14:14, Sheet2!2:2=G1))
The output is not correct answer, neither the its throwing any error.
I could save the output of filter(Sheet2!14:14,Sheet2!2:2=G1) in different cell and refer that cell in 2nd condition. But for that I need make plethora cells as I need to use this countifs function in every column.
PS : filter(Sheet2!14:14,Sheet2!2:2=G1) returns the correct value.
that's not how it works. the output of your FILTER formula needs to be exactly 609 cells to match the range of your COUNTIFS formula. only then your formula will work.
in your case try:
=COUNTA(IFNA(FILTER(A2:A; A2:A="yes"; REGEXMATCH(B2:B;
TEXTJOIN("|"; 1; FILTER(Sheet2!14:14; Sheet2!2:2=G1))))))

How to call Lua table value explicitly when using integer counter (i,j,k) in a for loop to make the table name/address?

I have to be honest that I don't quite understand Lua that well yet. I am trying to overwrite a local numeric value assigned to a set table address (is this the right term?).
The addresses are of the type:
project.models.stor1.inputs.T_in.default, project.models.stor2.inputs.T_in.default and so on with the stor number increasing.
I would like to do this in a for loop but cannot find the right expression to make the entire string be accepted by Lua as a table address (again, I hope this is the right term).
So far, I tried the following to concatenate the strings but without success in calling and then overwriting the value:
for k = 1,10,1 do
project.models.["stor"..k].inputs.T_in.default = 25
end
for k = 1,10,1 do
"project.models.stor"..j..".T_in.default" = 25
end
EDIT:
I think I found the solution as per https://www.lua.org/pil/2.5.html:
A common mistake for beginners is to confuse a.x with a[x]. The first form represents a["x"], that is, a table indexed by the string "x". The second form is a table indexed by the value of the variable x. See the difference:
for k = 1,10,1 do
project["models"]["stor"..k]["inputs"]["T_in"]["default"] = 25
end
You were almost close.
Lua supports this representation by providing a.name as syntactic sugar for a["name"].
Read more: https://www.lua.org/pil/2.5.html
You can use only one syntax in time.
Either tbl.key or tbl["key"].
The limitation of . is that you can only use constant strings in it (which are also valid variable names).
In square brackets [] you can evaluate runtime expressions.
Correct way to do it:
project.models["stor"..k].inputs.T_in.default = 25
The . in models.["stor"..k] is unnecessary and causes an error. The correct syntax is just models["stor"..k].

In Ruby is there a way to get the index of an item in an array that consists of structs?

With a normal array, I can use the arrayname.find_index('whatimlookingfor') to get the position within the array.
I can't figure out how to do this when the elements of the array are Struct's.
Scenario: I have a struct that consists of an ID and the Filename. In one function I need to find within that array the ID of a different file than the one I'm currently processing. I know the other filename, so what I was hoping that I could do something like:
arrayname.filename.find_index(parsedfilename)
But this obviously fails. Without iterating through the entire array is there a way to quickly reference the index of where the match happens? Or am I out of luck because the array is a collection of structs?
index (same as find_index) takes a block in which you can code up any true/false logic for your finder. To find the index of the first item whose filename does not match parsedfilename...
found_index = items.index { |item| item.filename != parsedfilename }
Many methods which work with Arrays and Enumerables also take blocks.

Looping multiple arrays

I have an array containing multiple arrays (the number may vary) of significant dimensions (an array may contain up to 150 objects).
With the array, I need to find a combination (one element for each sub-array) that matches a condition.
Due to the dimensions, I tried to use Enumerator::Lazy as follows
catch :match do
array[0].product(*array[1..-1]).lazy.each do |combination|
throw :match if ConditionMatcher.match(combination)
end
end
However, I realize when I call each the enumerator is evaluated and it performs very slowly.
I have tried to replace each with methods included in Enumerator::Lazy such as take_while
array[0].product(*array[1..-1]).lazy.take_while do |combination|
return false if ConditionMatcher.match(combination)
end
But also, in this case, the product is evaluated with low performance.
For better performance, even id I don't really like it, I'm thinking to replace product with a nested each loop. Something like
catch :match do
array[0].each do |first|
array[1].each do |second|
array[2].each do |third|
throw :match if ConditionMatcher.match([first, second, third])
end
end
end
end
Due to the fact that the number of sub-arrays changes from time to time. I'm not sure how to implement it.
Moreover, is there a better way to loop through all the sub-arrays without loading the entire set of combinations?
Update 1 -
Each sub-array contains an ActiveRecord::Relation on a polymorphic association. Therefore, each element of each combination responds to the same 2 methods (start_time and end_time) each returning an instance of Time.
The matcher checks if all the objects in the combination don't have overlapping times.
The problem is that Array#product already returns a huge array containing all combinations. With 3 sub-arrays containing 150 items each, it returns a 150 × 150 × 150 = 3,375,000 element array. Calling lazy on that array won't speed up anything.
To make product calculate the Cartesian product lazily (i.e. one combination after the other), you simply have to (directly) pass a block to it:
first, *others = array
first.product(*others) do |combination|
# ...
end

How to sort a Laravel collection with sortBy(), ascending, and have NULL values placed last instead of first

Laravel's Collection class (v5.5) has a sortBy() method that sorts everything similar to if you had used a SQL ORDER BY statement, except there is one striking difference: a relational database will put NULL values at the end when sorting ascending (or at least PostgreSQL does), but Laravel's sortBy() method puts NULL values first.
So how do I get those NULL values to be sorted last instead of first when using the Collection::sortBy() method? PLEASE NOTE: I cannot change the database query itself! MY ONLY OPTION is to sort the Collection itself within PHP. I absolutely cannot do this at the database level in my situation.
There is a similar question on Stack Overflow here but the solution OP found was kind of a hack and does not work in my situation, because I need it to work for varchars.
NOTE: I realize sortBy() accepts a Closure for the first argument but there is zero explanation in the documentation about the arguments this closure receives (which "key" is $key?), nor does it explicitly say what the closure is supposed to return in order to determine the sort order. (I'm assuming it should return an integer representing the order, but I do not know how to make that work for me with multiple NULL values.)
The sortBy method accepts a field on which to sort, in ascending order. So if you had a collection of App\User objects, you could pass in say first_name and that would sort by each user's first name.
If your logic is more complex, and you wanted to sort on something that isn't strictly a field of each item in your collection you may pass a closure instead. The first parameter passed to the closure is the actual item. You should return a value that you want to be sorted from the closure. Let's say in your collection of App\User objects, you wanted to sort by the last letter of each person's first name:
$users->sortBy(function ($item) {
return substr($item->first_name, -1);
});
The second parameter is the key, which is the key of the collection, or the underlying array it represents. If you've retrieved a collection from the database, this will likely be a numeric index, but if you had a different collection or you decided to re-key the collection by say, the user's email address (Using keyBy), then that is what is passed.
When it comes to sticking all of your null values at the end of the sorted result set, I would suggest using the sort method instead of sortBy. When you pass a closure to sort, it accepts two items, representing two items from your collection to be sorted. In the case of your collection of App\User objects, each item would an instance of App\User. This gives you total control on how two objects are compared and therefore total control over the order.
You should return -1 (or a negative value) if the first item is considered to be less than the second, you should return 0 if the two items are to be considered equal and 1 (or a positive value) if the first item is considered to be greater than the second.
$users->sort(function ($a, $b) {
// Return -1, 0 or 1 here
});
That should allow you to implement your logic. To ensure null values are moved to the end, just return 1 every time whatever you're interested in from $a is null. Similarly, if whatever you're interested in from $b is null, return -1 and if whatever you're interested in from both $a and $b are null, return 0.

Resources