Grails mapping sort on multiple fields :: Groovy sort on multiple map entries - sorting

Stumped on this one. In Grails it seems one cannot define a default sort on multiple columns in domain mapping a la static mapping = { sort 'prop1 desc, prop2 asc' }, or { sort([prop1:'desc', prop2:'asc']) }. Only first column gets sorted, lame.
Similarly, when trying to Groovy sort a Grails findAllBy query on multiple columns, the second sort overrides the first.
def list = [[rowNum:2,position:3],[rowNum:1,position:2],[rowNum:3,position:1]]
list.sort{it.rowNum}.sort{it.position}
Obviously missing the boat on the latter case, the groovy sort. I have seen postings re: implementing comparable, but looking for something more concise if possible.

Here is a Groovy solution. Still essentially implementing a Comparator though.
list.sort { map1, map2 -> map1.rowNum <=> map2.rowNum ?: map1.position <=> map2.position }

Thanks to the link from GreenGiant, we see that the issue is closed as fixed as of version 2.3.
There is also example code:
static mapping =
{ sort([lastname:'asc', name:'asc']) }
It is working for me in 2.4.3

You can use String.format if you know max length. I assumed max 10 lenght:
list.sort { String.format('%010d%010d', it.rowNum, it.position) }

Related

Is it possible to work with more than one array in vuetify v-autocomplete?

Normally one would just make a simple join to merge both arrays in one array, the problem is that i have arrays with different object structures, and depending on the type of object, i need to pass a different value.
Example:
array 1: fruits.type.name
array 2: animals.family.name
Is there any possibility other than having to craft a custom component from scratch using something like v-text-input, for example?
You mean something like this? Check this codesanbox I made:
https://codesandbox.io/s/stack-71429578-switch-autocomplete-array-757lve?file=/src/components/Example.vue
computed: {
autoArray() {
return this.typeAnimal ? this.animals : this.fruits
},
autoTypeId() {
return this.typeAnimal ? 'family.id' : 'type.id'
},
autoText() {
return this.typeAnimal ? 'family.name' : 'type.name'
}
}
With help of a couple computed props you could be able to switch array, item-text and item-value depending of the array you're working with.
As far as I know, there's no easy way to supply two different arrays to v-autocomplete and retain the search functionality.
You could probably join the arrays and write a custom filter property. Then use selection and item slots to change the output of the select based on the structure.
But if your data arrays aren't too complicated, I would avoid the above. Instead, I would loop through both arrays, and build a new combined one with a coherent structure.

Sorting and grouping in kotlin

I have a list of objects in the kotlin and I want to sort them by number and then by string. Is there a way to do this? I've gone through hundreds of articles, but nothing works anywhere.
myList.sortedWith(compareBy<Item> {it.name.id }.thenBy{it.name.secondname})
This code do not works.
Of course myList is a type of Item.
Greetings
#EDIT
But what if I have 10 same ids? The code will not reach the .thenBy check. Is there a possibility to check a whole pair of fields?
myList.sortedWith(compareBy<Item> {it.name.id }.thenBy{it.name.secondname}) returns a sorted copy of the list, but it doesn't modify the original one.
If you want the original list to be modified, you can either use sortWith instead of sortedWith:
myList.sortWith(compareBy<Item> { it.name.id }.thenBy { it.name.secondname })
Or reassign myList variable:
myList = myList.sortedWith(compareBy<Item> { it.name.id }.thenBy { it.name.secondname })

Sorting JDOM elements using Java API

I need your help with following issue:
In my code I have a list of elements, I need to sort this list according to 2 attributes: season and number.
List example:
<episode_list>
<episode id="280" number="13" season="1">
<title><![CDATA[Bowl Game]]></title>
</episode>
<episode id="314" number="12" season="1">
<title><![CDATA[Piss Test]]></title>
</episode>
<episode id="730" number="11" season="1">
I use Collections.sort(), but getting exception. As I understand I can't use it with JDOM Elements:
List<Element> episodes;
Collections.sort(episodes, new Comparator<Element>() {
#Override
public int compare(Element elem1, Element elem2) {
Integer seasonNumber1 = Integer.valueOf(myService.valueOfAttribute("season", elem1));
Integer seasonNumber2 = Integer.valueOf(myService.valueOfAttribute("season", elem2));
int seasonComp = seasonNumber1.compareTo(seasonNumber2);
if (seasonComp != 0) {
return seasonComp;
} else {
Integer episodeNumber1 = Integer.valueOf(myService.valueOfAttribute("number", elem1));
Integer episodeNumber2 = Integer.valueOf(myService.valueOfAttribute("number", elem2));
return episodeNumber1.compareTo(episodeNumber2);
}
}
});
Exception: java.util.Collections$UnmodifiableList$1.set(Unknown Source)
java.util.Collections.sort(Unknown Source)
Actually I don't need sorted xml, the only thing I need is the episode attribute "id" (for the lowest season and the lowest episode number).
What could you recommend? I have another implementation, where I go through all elements, but I don't think it's a nice solution...I also can create Java class Episode(id, episode, season), transform List to List and sort it, but also don't think it's a good idea. There is also sortContent method for Element, but I'm not sure how to implement it.
I'll appreciate any help.
Content attached to JDOM Elements cannot be sorted using the standard Collections.sort() mechanism because that process does not honour the only-attached-at-one-place-at-a-time rule for XML content.
JDOM has sort() methods built in to the Element class that allows you to sort the chile Elements or other Child content: See The Element.sortChildren() Javadoc for the JDOM way to do it.
Update: Also, for your reference, the error you are getting is because at some point you created an unmodifiable version of the List.... this is not something that happens from JDOM method calls. The error you are getting is because you are trying to modify a List that has been intentionally made read-only.
What's wrong with going through the list and finding the minimum. It is O(n), while sorting is O(n*log(n)). You might use a generic min function, such as the one in guava
Element firstEpisode = Ordering.from(your-comparator).min(episodes.iterator());
If you really want to sort it, why don't you sort new ArrayList<Element>(episodes) (I agree with rolfl that you cannot use Collections.sort for JDOM lists and that the error comes from your use of unmodifiable list).

OAuth - lexicographical byte value ordering in c#

I have written an Service Provider implementation for OAuth and one of the Devs found a bug in the way the implementation was ordering query parameters. I totally missed the lexicographical ordering requirement in the OAuth spec and was just doing a basic string sort on the name value parameters
Given the following URI request from the consumer:
http://api.com/v1/People/Search?searchfor=fl&communication=test#test.com&Include=addresses
The resulting signature base should order the parameters as:
Include=addresses, communication=test#test.com, searchfor=fl
Given the following URI request from the consumer:
http://api.com/v1/People/Search?searchfor=fl&communication=test#test.com&include=addresses
The resulting signature base should order the parameters as:
communication=test#test.com, include=addresses, searchfor=fl
Note the case difference in the querystring parameter "include". From what I understand, lexicographical byte value ordering will order parameters using the ascii value and then order asc.
Since I = 73 and i = 105, the capital I should be ordered before the lowercase i.
I have the following so far:
IEnumerable<QueryParameter> queryParameters = parameters
.OrderBy(parm => parm.Key)
.ThenBy(parm => parm.Value)
.Select(
parm => new QueryParameter(parm.Key, UrlEncode(parm.Value)));
But that will not cover the ascii character by character sort (IncLude=test&Include=test will not sort properly).
Any thoughts on how to make an efficient algorithm that will answer this problem? Or how to make the sort case sensitive via ICompare?
I solved the problem by creating a custom comparer, however, it seems clunky and I feel there must be a better way:
public class QueryParameterComparer : IComparer<QueryParameter> {
public int Compare(QueryParameter x, QueryParameter y) {
if(x.Key == y.Key) {
return string.Compare(x.Value, y.Value, StringComparison.Ordinal);
}
else {
return string.Compare(x.Key, y.Key, StringComparison.Ordinal);
}
}
}
Using the Ordinal string comparison is what did it for me. It does byte comparisons which is exactly what I needed.
Nick, as you've discovered StringComparison.Ordinal is the way to go. I just wanted to call out a caution that you sort AFTER you URI encode each of the keys and values.
BTW, there are already a few OAuth libraries out there, DotNetOpenAuth being my favorite (disclaimer: for biased reasons). Are you sure you want to build/maintain this one?
I had problem with the same expression (though it is not misspelled anymore in the OAuth documentation, - if that's the place where it was misspelled.)
Wikipedia sais, "lexicographical ordering" has meaning, when the letter ordering is given. It specifies the ordering of series of elements (letters) when the element's order is specified already.
It sounds reasonable to me. :).

Linq - what locale/collation it uses to compare objects?

When I call a Linq (not Linq-for-SQL, just simple in-memory Linq) - what locale it uses to compare objects, and how can I affect it?
E.g.
string[] a = { "a", "b", ... };
string max = a.Max();
What locale is used here - current, invariant? How can I affect it?
The comparision seems to be case-insensitive, what if I want to find case-sensitive max?
It uses the implementation of IComparable<string> in string.
You could fairly easily write your own version of Max which does take an IComparer<T> for comparisons - I'm very surprised there isn't one already. Alternatively, you could use Aggregate in a somewhat cumbersome way to accomplish the same result.
I decided to take a deeper look on what happening.
Max method uses Comparer class to compare items. Comparer class in turn uses GenericComparer.Compare method. This method calls String.CompareTo method. CompareTo uses following code:
CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, CompareOptions.None);
That said, you can affect behavior of Max method by changing
Thread.CurrentThread.CurrentCulture
If it's unacceptable, you have to roll out your own version of Max as Jon suggested.
Posting my code based on Jon's suggestion:
static T Max<T>(this IEnumerable<T> coll, IComparer<T> comp)
{
return coll.Aggregate((a, b) => comp.Compare(a, b) < 0 ? b : a);
}
It can be used as
string max = coll.Max(StringComparer.OrdinalIgnoreCase);

Resources