www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Function which returns a sorted array without duplicates

reply dan <dan.hitt gmail.com> writes:
I would like to write a function which takes an array as input, 
and returns a sorted array without duplicates.

In fact, i have a function which does this, but i think it may 
have some extra unnecessary steps.

```d
     private S[] _sort_array( S )( S[] x ) {
       import std.algorithm;
       auto y = x.dup;
       y.sort;
       auto z = y.uniq;
       // Cannot just return z; this gives:
       // Error: cannot implicitly convert expression `z` of type
       // `UniqResult!(binaryFun, uint[])` to `uint[]`
       //
       // You also cannot just return cast( S[] ) z;
       //
       // Nor can you do:
       //  import std.conv;
       //  return to!( S[] )( z );
       typeof( x ) w;
       foreach ( v ; z ) w ~= v;
       return w;
     }
```

My only constraint is that i really want to keep the same 
signature (i.e., return an array, not sharing structure or 
storage with the input).

Here's the usage:

```d
     void main( ) {
       uint[] nums = [1, 3, 2, 5, 1, 4, 2, 8];
       auto sorted = _sort_array( nums );
       import std.stdio;
       writeln( "Input:  ", nums );
       writeln( "Output: ", sorted );
     }
```

Thanks in advance for any info!

dan
Jan 21 2023
parent reply evilrat <evilrat666 gmail.com> writes:
On Sunday, 22 January 2023 at 04:42:09 UTC, dan wrote:
 I would like to write a function which takes an array as input, 
 and returns a sorted array without duplicates.


 ```d
     private S[] _sort_array( S )( S[] x ) {
       import std.algorithm;
       auto y = x.dup;
       y.sort;
       auto z = y.uniq;
       // Cannot just return z; this gives:
       // Error: cannot implicitly convert expression `z` of type
       // `UniqResult!(binaryFun, uint[])` to `uint[]`
uniq and other algorithms often returns a lazy range, you can build an array by using `std.array.array()` https://dlang.org/phobos/std_array.html#array try something like this or just `return array(y.uniq);` ```d private S[] _sort_array( S )( S[] x ) { import std.algorithm; import std.array; return x.dup .sort .uniq .array(); } ``` And IIRC you probably don't need `dup` as sort produces a lazy range.
Jan 21 2023
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 1/21/23 23:33, evilrat wrote:

 And IIRC you probably don't need `dup`
Unfortunately, no. Skipping .dup is only possible if we are allowed to sort the original array.
 as sort produces a lazy range.
sort() returns a SortedRange but it can't be lazy. Even if it were, the first call to .front would have to sort anyway. However... There is an optimization possible for such requirements if not all elements but just a number of them are needed. For example, if only the first 10 elements are needed, then a binary heap may be faster: https://dlang.org/phobos/std_container_binaryheap.html The usage would be similar to the following for "the first 10 unique elements": heapify(arr).uniq.take(10) (Not tested.) Ali
Jan 22 2023
prev sibling parent reply dan <dan.hitt gmail.com> writes:
On Sunday, 22 January 2023 at 07:33:01 UTC, evilrat wrote:
 On Sunday, 22 January 2023 at 04:42:09 UTC, dan wrote:
 I would like to write a function which takes an array as 
 input, and returns a sorted array without duplicates.


 ```d
     private S[] _sort_array( S )( S[] x ) {
       import std.algorithm;
       auto y = x.dup;
       y.sort;
       auto z = y.uniq;
       // Cannot just return z; this gives:
       // Error: cannot implicitly convert expression `z` of 
 type
       // `UniqResult!(binaryFun, uint[])` to `uint[]`
uniq and other algorithms often returns a lazy range, you can build an array by using `std.array.array()` https://dlang.org/phobos/std_array.html#array try something like this or just `return array(y.uniq);` ```d private S[] _sort_array( S )( S[] x ) { import std.algorithm; import std.array; return x.dup .sort .uniq .array(); } ``` And IIRC you probably don't need `dup` as sort produces a lazy range.
Thanks evilrat, this works perfectly, and is just the right style too (imvho). So what i was missing was std.array. Thanks also Ali for your subsequent clarifying remarks. (Probably what i need to do is read a good book on the std library for d.) dan Thanks also Ali for your subsequent remarks
Jan 22 2023
parent Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 22 January 2023 at 23:26:45 UTC, dan wrote:
 So what i was missing was std.array.
Of course you can use the uniq from Phobos. But since we already use array, you should also try the 3rd classic version: ```d import std.algorithm; import std.array; // qef. version: private S[] sortArray ( S )( S[] x ) { auto y = x.dup; return y.sort.uniq.array; } // no dup. version: private S[] sortArrayy ( S )( S[] x ) { S[] w; foreach ( v ; x ) w ~= v; return w.sort.uniq.array; } // classic version: private S[] sortArrayyy ( S )( S[] x ) { S[] w = x.dup; w.sort; size_t diff; for (size_t j, i = 1; i < w.length; ++i) { if (w[j] != w[i]) { w[++j] = w[i]; } else { ++diff; } } return w[0 .. $ - diff]; } void main() { uint[] nums = [1, 3, 2, 5, 1, 4, 2, 8]; auto sorted = nums.sortArray; assert(sorted.equal(nums.sortArrayy)); assert(sorted.equal(nums.sortArrayyy)); import std.stdio; writeln( "Input: ", nums ); writeln( "Output: ", sorted ); } ``` In fine, we have implemented 3 ways to sort an array and return it without repetition. I guess, there is no alternative to this basic algorithm... SDB 79
Jan 22 2023