views:

344

answers:

2

I'm implementing a LINQ clone in Lua, but that's not too relevant here, and I've got most features done (enumerable/queryable, not the precompiler yet), but can't think of a smart way to implement OrderBy's ThenBy.

Currently I sort once, then place in new lists and then sort those sub lists and finally merge the results again, but that seems very wasteful and inelegant, I'm sure someone has figured out a smart way to do this (better algorithm), but I have no idea what it is. Any clues as to how to implement OrderBy / Thenby in an efficient way?

Note: Language and Language constructs hopefully are not relevant here, I'm looking for the generalized algorithm, just as say a Binary Sort can be done in any language.

Edit: Currently I'm working on LINQ to Object, so any ideas how that would be done in particular would be great. I'm guessing OrberBy/ThenBy are 2 function calls, not one but I might be wrong.

+3  A: 

Typically you would implement a multi-key sort by using a suitable compare method. For example, to sort a list of names by last name and then first name, you might use a compare function like this:

int compareNames(Name n1, Name n2)
{
    if (n1.LastName < n2.LastName) {
        return -1;
    } else if (n1.LastName > n2.LastName) {
        return 1;
    } else if (n1.FirstName < n2.FirstName) {
        return -1;
    } else if (n1.FirstName > n2.FirstName) {
        return 1;
    } else {
        return 0;
    }
}

The key point here is that we don't look at the FirstName member unless we already know that the two LastName members are equal.

Greg Hewgill
But shouldn't a OrderBy/ThenBy be done in two different function calls?
Robert Gould
@Robert - at least with Linq2SQL it uses the whole chain of methods to produce a single expression that accomplishes the desired result. Depending on whether your clone uses deferred execution or not it may result in collapsing orderby/thenby into a single comparison.
tvanfosson
Can this be done with true and false only?
Robert Gould
I'm not sure what you mean by "true and false only". My example compare function compares two elements (n1, n2) and returns -1 if n1 < n2, 0 if n1 == n2, and 1 if n1 > n2.
Greg Hewgill
I meant that 1 and -1 are both true. 0 is false (in most cases). Was wondering if the sign +/- has any effect on your sorter (the function that calls the sort algorithm over the set)
Robert Gould
Yes, of course it does, otherwise how would the sorter know which order to place the elements in? An example sorter function of this type would be qsort() from the C standard library: http://www.cplusplus.com/reference/clibrary/cstdlib/qsort.html
Greg Hewgill
There are other ways of defining the comparator function too, for example the C++ STL function sort() uses a comparator that returns true if its first argument is *less than* the second argument: http://www.cplusplus.com/reference/algorithm/sort.html
Greg Hewgill
The sorter I'm working with is like that of the C++ STL sort(), so it requires the righthand less than lefthand to be true or false. Anyways now its clear, thanks
Robert Gould
+1  A: 

I think this also works:

function(lh,rh)
    if lh.first < rh.first then
     return true
    elseif lh.second < rh.second then
     return true
    end
    return false
end

which, if true, means this should work:

tests={}
tests[1]=function(lh,rh) 
    return lh.first < rh.first
end
tests[2]=function(lh,rh)
    return lh.second < rh.second
end

function(lh,rh)
    local res=true
    local k,v
    for k,v in ipairs(tests) do
     res = v(lh,rh)
     if res then break end
    end
    return res
end
Robert Gould