Ordering items by sizename when it's not alphabetically logic? - ruby-on-rails

In my app, the admin may add sizes to his products in this order.
Variant.create(size_name: "L")
Variant.create(size_name: "S")
Variant.create(size_name: "XXL")
Variant.create(size_name: "XL")
Sizes could also be (30,24, 33, 31, 29)
In my product view, the select tag display in the order it has been created.
I would like to sort from the smallest size to the biggest (S, M, L ...).
With the numerically sizes,I can order from the smallest to the biggest it's Okay
How I am supped to make sure that both sizes (the numerically and the alphabetically) could be sorted from the smallest to the biggest?

There are many ways to solve this, but at the core of any solution you need to define the order manually (or use a third party library which has already written this manual ordering for you?).
For example, you could somewhere define e.g.
SIZE_NAMES = %w[XS S M L XL XXL]
and then elsewhere in the code, use something like:
variants.sort_by { |variant| SIZE_NAMES.index(variant.size) }
For a more "advanced" solution, you could instead consider defining each size as a custom object rather than a regular String. Take a look at the Comparable module, and the <=> ("spaceship") operator.
By utilising this, you could potentially implement it in such a way that e.g. variants.sort will automatically compare variants by their "converted" size, and order them as you expect.

If you wish to do sorting on db side then you have two options:
Predefined sort like so:
Variant.order(
"CASE size_name
WHEN 'S' THEN 1
WHEN 'L' THEN 2
WHEN 'XL' THEN 3
WHEN 'XXL' THEN 4
ELSE 10
END, size, id"
)
You might want to move it to scope so in case you need to add another size_name there is only one place to change
With active record enums:
enum size_name: { s: 0, l: 1, xl: 2, xxl: 3 }
That way, you can still assign the field by the string/symbol, but the underlying data will actually be an integer, so you can just use order(:size_name, :size) to sort by size_name and size.
Also this way you can add index to speed up ordering

Related

Neo4j- typical query - returning a node with the most appearances

I have to make a query that returns me a club or clubs, where play the most amount of players that are not representing the country, from where the club is.
My query works fine, but I want to filter, so my result is ONLY clubs that size is the most.
As for now the biggest size is 4, and I have 4 clubs that have 4 players which were supposed to be there.
The only thing comes to my mind to filter it out was by using LIMIT 1 in the end, but then, I cut out three clubs, that also fill the predicate.
MATCH (c: Club)<-[r: PLAYS_FOR]-(p: Player)-[r2: REPRESENTS]->(n: NationalTeam)
WHERE c.country<>n.country
WITH c,collect(p.name) as list_players,n.country as country,size(collect(p.name)) as size
RETURN c,list_players,country,size ORDER BY size DESC LIMIT 1
edit:
I managed to do something like this, don't know if it's optimal, but it is working:
MATCH (c: Club)<-[r: PLAYS_FOR]-(p: Player)-[r2: REPRESENTS]->(n: NationalTeam)
WHERE c.country<>n.country
WITH c,collect(p.name) as list_players,n.country as country,size(collect(p.name)) as size
WITH c,list_players,country,size ORDER BY size DESC LIMIT 1
WITH size
MATCH (c: Club)<-[r: PLAYS_FOR]-(p: Player)-[r2: REPRESENTS]->(n: NationalTeam)
WHERE c.country<>n.country
WITH size,c,collect(p.name) as list_players,n.country as country,size(collect(p.name)) as size2 WHERE size(collect(p.name)) = size
RETURN c,list_players,country,size
If you install APOC Procedures, there is an aggregation function you can use to get the items associated with a maximum value, and this works even when multiple items are tied for that value: apoc.agg.maxItems()
The trouble now is that all the club-specific data needs to be encapsulated into the item itself, so you'll need to add them to a map and use the map as the item, and the size of the person collection as the value.
Also your aggregation isn't quite correct. You're collecting player names, but you have the country of the player as a part of the grouping key (when you aggregate, all non-aggregation terms form the grouping key), and that isn't likely want you want. Maybe you wanted the country of the club instead?
Try working from this:
MATCH (c: Club)<-[r: PLAYS_FOR]-(p: Player)-[r2: REPRESENTS]->(n: NationalTeam)
WHERE c.country<>n.country
WITH c,collect(p) as list_players
WITH apoc.agg.maxItems({club:c, players:list_players}, size(list_players)) as maxResults
UNWIND maxResults.items as result
WITH result.club as c, [player IN result.players | player.name] as list_players, maxResults.value as size
RETURN c,list_players,size

Lua: Sort table of numbers with multiple dots

I have a table of strings like this:
{
"1",
"1.5",
"3.13",
"1.2.5.7",
"2.5",
"1.3.5",
"2.2.5.7.10",
"1.17",
"1.10.5",
"2.3.14.9",
"3.5.21.9.3",
"4"
}
And would like to sort that like this:
{
"1",
"1.2.5.7",
"1.3.5",
"1.5",
"1.10.5",
"1.17",
"2.2.5.7.10",
"2.3.14.9",
"2.5",
"3.5.21.9.3",
"3.13",
"4"
}
How do I sort this in Lua? I know that table.sort() will be used, I just don't know the function (second parameter) to use for comparison.
Given your requirements, you probably want something like natural sort order. I described several possible solution as well as their impact on the results in a blog post.
The simplest solution may look like this (below), but there are 5 different solutions listed with different complexity and the results:
function alphanumsort(o)
local function padnum(d) return ("%03d%s"):format(#d, d) end
table.sort(o, function(a,b)
return tostring(a):gsub("%d+",padnum) < tostring(b):gsub("%d+",padnum) end)
return o
end
table.sort sorts ascending by default. You don't have to provide a second parameter then. As you're sorting strings Lua will compare the strings character by character. Hence you must implement a sorting function that tells Lua which comes first.
I just don't know the function (second parameter) to use for
comparison.
That's why people wrote the Lua Reference Manual
table.sort (list [, comp])
Sorts the list elements in a given order, in-place, from list1 to
list[#list]. If comp is given, then it must be a function that
receives two list elements and returns true when the first element
must come before the second in the final order, so that, after the
sort, i <= j implies not comp(list[j],list[i]). If comp is not given,
then the standard Lua operator < is used instead.
The comp function must define a consistent order; more formally, the
function must define a strict weak order. (A weak order is similar to
a total order, but it can equate different elements for comparison
purposes.)
The sort algorithm is not stable: Different elements considered equal
by the given order may have their relative positions changed by the
sort.
Think about how you would do it with pen an paper. You would compare each number segment. As soon as a segment is smaller than the other you know this number comes first.
So a solution would probably require you to get those segments for the strings, convert them to numbers so you can compare their values...

table size difference. are both examples identical?

tNum={[2]=true , [3]=true,[4]=true, [5]=true ,[6]=true }
#tNum-->0
tNum={}
tNum[2]=true
tNum[3]=true
tNum[4]=true
tNum[5]=true
tNum[6]=true
#tNum-->6
why such a difference in size?
are both examples identical?
Your two tables are semantically identical, but using # on them is ambiguous. Both 0 and 6 are correct lengths. Here's an abridged version of the docs:
The length operator applied on a table returns a border in that table. A border in a table t is any natural number that satisfies the following condition:
(border == 0 or t[border] ~= nil) and t[border + 1] == nil
A table with exactly one border is called a sequence.
When t is not a sequence, #t can return any of its borders. (The exact one depends on details of the internal representation of the table, which in turn can depend on how the table was populated and the memory addresses of its non-numeric keys.)
This is an example of undefined behavior (UB). (That may not be the right word, because the behavior is partially defined. UB in Lua can't launch nuclear weapons, as it can in C.) Undefined behavior is important, because it gives the devs the freedom to choose the fastest possible algorithm without worrying about what happens when a user violates their assumptions.
To find a length, Lua makes, at most, log n guesses instead of looking at every element to find an unambiguous length. For large arrays, this speeds things up a lot.
The issue is that when you define a table as starting at index [2], the length operator breaks because it assumes that tables start at index [1].
The following code works as intended:
tNum = {[1]=false, [2]=true, [3]=true, [4]=true, [5]=true, [6]=true}
#tNum => 6
The odd behaviour is caused because when you initialize an array with tNum={} it initializes by assigning every index to nil, and the first index is [1] (It doesn't actually initialize every value to nil, but it's easier to explain that way).
Conversely, when you initialize an array with tNum={[2]=true} you are explicitly telling the array that tNum[1] does not exist and the array begins at index 2. The length calculation breaks when you do this.
For a more thorough explanation, see this section of the lua wiki near the bottom where it explains:
For those that really want their arrays starting at 0, it is not difficult to write the following:
days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
Now, the first value, "Sunday", is at index 0. That zero does not affect the other fields, but "Monday" naturally goes to index 1, because it is the first list value in the constructor; the other values follow it. Despite this facility, I do not recommend the use of arrays starting at 0 in Lua. Remember that most functions assume that arrays start at index 1, and therefore will not handle such arrays correctly.
The Length operator assumes your array will begin at index [1], and since it does not, it doesn't work correctly.
I hope this was helpful, good luck with your code!

SSRS: Adding a filter that returns information from entire group

I am trying to create a report in SSRS. Below is a small example of what my dataset looks like.
Example Data Set
So, there are three different stores (A,B,C) and each has a landlord (a,b,c). Landlords can pay via three different methods (1,2,3) and the amounts paid per method are shown.
Right now, I have two filters set up. The first is by Store and the second is by Landlord.
What I am having trouble with is:
How can I set up a filter by the Amount that will return information from an entire Store/Landlord?
So for example, if I wanted to filter Amount by 150, I would like to return all the "payment" information for the store(s) that have a payment of 150. Such as the following:
Desired Result
Is it possible to add a filter to return information from the entire group? (Store and Landlord are the group in this case)
I am new to SSRS so any help/insight would be greatly appreciated!
You can use LookUpSet to locate the matching groups, JOIN to put the results in a string and the INSTR function to filter your results.
=IIF(ISNOTHING(Parameters!AMOUNT.Value) OR INSTR(
Join(LOOKUPSET(Fields!Amount.Value, Fields!Amount.Value, Fields!Store.Value, "DataSet1"), ", ") ,
Fields!Store.Value
) > 0, 1, 0)
This translates to:
If the Store value is found (INSTR > 0) in the list (JOIN) of Stores where the Amount is the current Amount (Lookupset).
In your filter, put the above expression in the Expression, change the type to INTEGER and the Value to 1.
[

Ruby on Rails method to calculate percentiles - can it be refactored?

I have written a method to calculate a given percentile for a set of numbers for use in an application I am building. Typically the user needs to know the 25th percentile of a given set of numbers and the 75th percentile.
My method is as follows:
def calculate_percentile(array,percentile)
#get number of items in array
return nil if array.empty?
#sort the array
array.sort!
#get the array length
arr_length = array.length
#multiply items in the array by the required percentile (e.g. 0.75 for 75th percentile)
#round the result up to the next whole number
#then subtract one to get the array item we need to return
arr_item = ((array.length * percentile).ceil)-1
#return the matching number from the array
return array[arr_item]
end
This looks to provide the results I was expecting but can anybody refactor this or offer an improved method to return specific percentiles for a set of numbers?
Some remarks:
If a particular index of an Array does not exist, [] will return nil, so your initial check for an empty Array is unnecessary.
You should not sort! the Array argument, because you are affecting the order of the items in the Array in the code that called your method. Use sort (without !) instead.
You don't actually use arr_length after assignment.
A return statement on the last line is unnecessary in Ruby.
There is no standard definition for the percentile function (there can be a lot of subtleties with rounding), so I'll just assume that how you implemented it is how you want it to behave. Therefore I can't really comment on the logic.
That said, the function that you wrote can be written much more tersely while still being readable.
def calculate_percentile(array, percentile)
array.sort[(percentile * array.length).ceil - 1]
end
Here's the same refactored into a one liner. You don't need an explicit return as the last line in Ruby. The return value of the last statement of the method is what's returned.
def calculate_percentile(array=[],percentile=0.0)
# multiply items in the array by the required percentile
# (e.g. 0.75 for 75th percentile)
# round the result up to the next whole number
# then subtract one to get the array item we need to return
array ? array.sort[((array.length * percentile).ceil)-1] : nil
end
Not sure if it's worth it, but here is how I did it for the quartiles:
def median(list)
(list[(list.size - 1) / 2] + list[list.size / 2]) / 2
end
numbers = [1, 2, 3, 4, 5, 6]
if numbers.size % 2 == 0
puts median(numbers[0...(numbers.size / 2)])
puts median(numbers)
puts median(numbers[(numbers.size / 2)..-1])
else
median_index = numbers.index(median(numbers))
puts median(numbers[0..(median_index - 1)])
puts median(numbers)
puts median(numbers[(median_index + 1)..-1])
end
If you're calculating both quartiles, you might want to move the "sort" outside the function, so that it only needs to be done once. This also means you aren't modifying your caller's data (sort!), nor making a copy every time the function is called (sort).
I know, premature optimisation and all that. And it's a bit awkward for the function to say, "the array must be sorted before calling this function". So it's reasonable to leave it as it is.
But sorting already-sorted data is going to take considerably longer than the whole rest of the function put together(*). It also has higher algorithmic complexity: O(N) at best, when the function could be O(1) for the second quartile (although O(N log N) for the first one if the data is not already sorted, of course). So it's worth avoiding if performance might ever be an issue for this function.
There are slightly faster ways of finding the two quartiles than a full sort (look up "selection algorithms"). For instance if you're familiar with the way qsort uses pivots, observe that if you need to know the 25th and 75th items out of 100, and your pivot at some stage ends up in position 80, then there's absolutely no point recursing into the block above the pivot. You really don't care what order those elements are in, just that they're in the top quartile. But this will considerably increase the complexity of the code compared with just calling a library to sort for you. Unless you really need a minor performance boost, I think you're good as you are.
(*) Unless ruby arrays have a flag to remember they're already sorted and haven't been modified since. I don't know whether they do, but if so then using sort! a second time is of course free.

Resources