Thread overview
Function which returns a sorted array without duplicates
Jan 22, 2023
dan
Jan 22, 2023
evilrat
Jan 22, 2023
Ali Çehreli
Jan 22, 2023
dan
Jan 23, 2023
Salih Dincer
January 22, 2023

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.

    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:

    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

January 22, 2023

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.

    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);

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.

January 22, 2023
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

January 22, 2023

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.

    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);

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

January 23, 2023

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:

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