sorting list #sort - sorting

I wanted to sort 'Country' list by name, then 'China' must always be on top of the drop down list...
Here is my code..
<option value="">Country...</option>
<t t-foreach="all_country.sorted(key=lambda x:x.name, reverse=False)" t-as="x">
<option t-att-value="x.id" t-att-selected="int(x.id) == int(((country_id or -1) if country_id else -1))">
<t t-esc="x.name"/>
</option>

You have to change your sort key to return a tuple with False if you find "China", then False if you find "Japan", then the actual value.
So if name is not "China" or "Japan", all is True and you have natural sorting order, but for those 2, you get False,True and True,False and natural sorting order of the tuple makes them come first:
change your key argument as follows:
key=lambda x:(x.name!="China",x.name!="Japan",x.name)
note that you don't need reverse=False. This is default.

Just code them hard before you enter the loop and then skip if they come up

Related

How to choose option of select control in Cypress based on default value?

Below is a select control in my app:
<select id="answer">
<option value="yes"> Yes <option>
<option value="no"> No <option>
<option value="maybe"> Maybe <option>
</select>
One of the above values will always be selected by default when the page loads.
A problem I have is that I won't know what that default value will be each time.
Here is an example of the Cypress test I'm trying to write:
Given the select control is visible
When I select a different option
Then the selected option is updated
Here's what I am trying to do in pseudo-code:
cy.get('select').select(~~ any option that isn't the default value ~~)
Is it possible to write something like the above? I just want to update the selected option to something other than the default value (but I won't know that default value until during the test, as it will be random)
Example of how it would work during a test run:
The page loads & the default selected option is 'No'
Cypress should get the default selected value ('no')
Then select an option that is not equal to 'no'
Validate the selected option value is 'no'
Example of how the test might run a second time:
The page loads & the default selected option is 'Maybe'
Cypress should get the default selected value ('maybe')
Then select an option that is not equal to 'maybe'
Validate the selected option value is 'maybe'
The random starting value is a bit of an anti-pattern for testing.
Maybe try to force the initial value to be the 1st, then cycle through the options.
const options = ['yes', 'no', 'maybe']
function nextOption(current) {
return (options.indexOf(current) + 1) % options.length
}
function selectAnotherOption() {
cy.get('select')
.invoke('val')
.then(current => {
cy.get('select').select(nextOption(current))
})
}
cy.get('select').select('Yes')
cy.get('select').should('have.value', 'yes')
selectAnotherOption()
cy.get('select').should('have.value', 'no')
selectAnotherOption()
cy.get('select').should('have.value', 'maybe')
selectAnotherOption()
cy.get('select').should('have.value', 'yes')
I had a crack at making the above test "blind" (starting from any random value) but frankly the test gets awfully complicated and it's hard to know if you're testing anything of value.
You can grab the value of the element on load, and use the option underneath the select to find one that does not equal the initial value.
cy.get('select')
.invoke('val')
.then((val) => {
cy.get('select').find('option').then(($options) => {
const notSelected = $options.filter((x) => $options[x].value !== val);
const ranNum = Math.floor(Math.random() * notSelected.length);
cy.get('select').select(notSelected[ranNum].value);
});
});

Group list of objects/AR relation by user_id

I have a list of objects which is actually AR Relation. My object has these fields :
{
agreement_id: 1,
app_user_id: 1,
agency_name: 'Small business 1'
..etc..
},
{
agreement_id: 2,
app_user_id: 1,
agency_name: 'Small business 2'
..etc..
}
I m representing my object as a Hash for easier understanding. I need to map my list of objects to format like this :
{
1 => [1,2]
}
This represents a list of agreement_ids grouped by the user. I always know which user I m grouping on. Here is what I've tried so far :
where(app_user_id: user_id).where('...').select('app_user_id, agreement_id').group_by(&:app_user_id)
This gives me the structure what I want but not exactly the data that I want, here is an output of this :
{1=>
[#<Agreement:0x6340fdbb agreement_id: 1, app_user_id: 1>,
#<Agreement:0x91bd4dd agreement_id: 2, app_user_id: 1>]
}
I've also thought I was going to be able to do this with map method, and here is what I tried :
where(app_user_id: user_id).where('....').select('app_user_id, agreement_id').map do |ag|
{ ag.app_user_id => ag.agreement_id }
end.reduce(&:merge)
But it only produces the mapping with the last agreement_id like this :
{1=>2}
I've tried some other things not worth mentioning. Can anyone suggest a way that would make this work?
This might work :
where(app_user_id: user_id)
.where('...')
.select('app_user_id, agreement_id')
.group_by(&:app_user_id).map{|k,v| Hash[k, v.map(&:agreement_id)]}
Try this one
where(app_user_id: user_id).
where('...').
select('app_user_id, agreement_id').
map { |a| [a.app_user_id, a.agreement_id] }.
group_by(&:first)

Get the count of duplicate keys in a hash

I have a hash say
test = [ {:a1=>"a", :b1=>"q"},
{:a1=>"c", :b1=>"z"},
{:a1=>"a", :b1=>"zcq"} ]
Need to find out count of key with "a" (e.g. :a1=>"a") in a hash. The output should be 2 if i am searching for key as "a".
How to find the count of the selected key.
Try this one
test.count { |item| item[:a1] == 'a' }

Most efficient way to extract an item from a Ruby array of hashes

I have some large Ruby structures that I need to quickly extract data from. I have no control over the format of the data, although I'm open to transforming it under certain circumstances. What is the most efficient way to extract a single item from the following hash, when using the displayName as the 'key'.
[
{'displayName'=>'Some Key 1', 'values'=>[1,2,3]},
{'displayName'=>'Some Key 2', 'values'=>["Some text"]},
{'displayName'=>'Some Key 3', 'values'=>["Different text","More text"]},
{'displayName'=>'Some Key 4', 'values'=>[2012-12-12]}
]
Each hash has other keys in it that I've removed to assist understanding.
The challenge is that in certain circumstances, the displayName field will need to be matched on a prefix sub-string. Does anybody have any practical experience knowing when to use .each and match manually, or .select to get the common case exact matches and fallback for the prefixes afterwards. Or is there some common trick I'm missing.
If you're doing this once, you'll probably just have to iterate over the set and find what you need:
row = data.find do |row|
row['displayName'] == name
end
row && row['values']
If you're doing it more than once, you should probably make an indexed structure out of it with a simple transform to create a temporary derivative structure:
hashed = Hash[
data.collect do |row|
[ row['displayName'], row['values'] ]
end
]
hashed[name]
You can use simple select thought it may no be as fast as it could with large sized arrays:
data = [
{'displayName'=>'Some Key 1', 'values'=>[1,2,3]},
{'displayName'=>'Some Key 2', 'values'=>["Some text"]},
{'displayName'=>'Some Key 3', 'values'=>["Different text","More text"]},
{'displayName'=>'Some Key 4', 'values'=>[2012-12-12]}
]
data.select { |e| e['displayName'] == 'Some Key 2' }.first
You can group_by the desired key instead, wich will make access faster
hashed_data = data.group_by { |e| e['displayName'] }
hashed_data['Some Key 4']
=> [{"displayName"=>"Some Key 4", "values"=>[1988]}]

Use LINQ for arbitrary sorting

Let's say we have an entity that has attributes att1 and att2, where att1 can have values a,b,c and att2 can have values 1,2,3. Is it possible to use LINQ so that we can sort items in the collection by applying arbitrary sorting rule without implementing IComparable. I am facing an issue were business requires that on some screens items in the collection be sorted one way and in other screens some other way. For example rule can state that items need to be sorted so that "b" is listed first, then "a", then "c" and within each group, "3" is first, then "1" then "2".
Sure. You can use OrderBy with a predicate that returns more or less whatever kind of arbitrary "sort order" you please. For example:
objectsWithAttributes.OrderBy(x =>
{
// implement your "rules" here -- anything goes as long as you return
// something that implements IComparable in the end. this code will sort
// the enumerable in the order 'a', 'c', 'b'
if (x.Attribute== 'a')
return 0;
else if (x.Attribute== 'c')
return 1;
else if (x.Attribute== 'b')
return 2;
}).ThenBy(x =>
{
// implement another rule here?
});

Resources