Proxy sorting

Steven Schveighoffer schveiguy at yahoo.com
Fri Feb 18 05:19:59 PST 2011


On Fri, 18 Feb 2011 08:08:22 -0500, bearophile <bearophileHUGS at lycos.com>  
wrote:

> This is a RosettaCode simple task:
> http://rosettacode.org/wiki/Sort_disjoint_sublist#D
>
> Given a list of values and a set of integer indices into that value  
> list, sort the values at the given indices, but preserving the values at  
> indices outside the set of those to be sorted.
>
> Example input:
>   values: [7, 6, 5, 4, 3, 2, 1, 0]
>   indices: {6, 1, 7}
>
> Output:
>   [7, 0, 5, 4, 3, 2, 1, 6].
>
>
> I'd like to solve the problem using std.algorithm.sort, creating an  
> array of proxy things, that while they get sorted, sort the original  
> items too. Is it possible? This is a first try, but it doesn't work. I  
> think struct postblits aren't useful here (currently disjointSort can't  
> use a map() because of a map() bug I've added to bugzilla few days ago,  
> so I use just a foreach+append).
>
>
> import std.stdio, std.algorithm, std.array;
>
> struct Proxy(T) {
>     T* item;
>
>     int opCmp(ref const Proxy other) {
>         if (*item < *(other.item))
>             return -1;
>         else
>             return *item > *(other.item);
>     }
>
>     void opAssign(Proxy other) {
>         if (item != null)
>             *item = *(other.item);
>         item = other.item;
>     }
> }
>
> Proxy!T proxy(T)(ref T item) {
>     return Proxy!T(&item);
> }
>
> void disjointSort(T, U)(T[] arr, U[] s) {
>     auto idxSet = array(uniq(s.sort()));
>     auto proxies = new Proxy!T[idxSet.length];
>     foreach (i, idx; idxSet)
>         proxies[i] = proxy(arr[idx]);
>     proxies.sort();
> }
>
> void main() {
>     auto data = [7, 6, 5, 4, 3, 2, 1, 0];
>     auto indexes = [6, 1, 1, 7];
>     disjointSort(data, indexes);
>     writeln(data);
> }
>
>
> Here I think opAssign() is not used by the swap() used by sort().

I think opAssign is incorrect.

Think about a standard swap:

swap(ref Proxy p1, ref Proxy p2)
{
   auto ptmp = p1;
   p1 = p2;
   p2 = ptmp;
}

Let's expand it out to the assignments that happen:

ptmp.item = p1.item;
*p1.item = *p2.item; // at this point, both ptmp.item and p1.item point to  
the *same element*, so you are also effectively assigning *ptmp.item
p1.item = p2.item;
*p2.item = *ptmp.item;
p2.item = ptmp.item;

If you passed in items that point to 1 and 2 respectively, I'd expect the  
pointers to be swapped, but both values set to 2.

My suggestion would be to create a bidirectional proxy range that uses a  
supplemental array to determine where the "next/previous" element is (i.e.  
the index array).  Should be pretty simple.  Then just pass this to sort.

-Steve


More information about the Digitalmars-d-learn mailing list