## digitalmars.D.learn - Reducing an array

Tim Holzschuh via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
```Hi there,

I try to remove all equal elements of an array, thus [2,2] --> [2].

I thought this maybe would be possible with std.algorithm.reduce, but at
least the way I tried it doesn't work:

arr.reduce( (a,b) => a != b );

Is there a simple solution using Phobos-functions?

Thank you,
Tim
```
Apr 17 2014
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
```On Thu, 17 Apr 2014 09:46:25 -0400, Tim Holzschuh via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:

Hi there,

I try to remove all equal elements of an array, thus [2,2] --> [2].

I thought this maybe would be possible with std.algorithm.reduce, but at
least the way I tried it doesn't work:

arr.reduce( (a,b) => a != b );

reduce doesn't do what you think it does. It applies a function to all
elements, keeping track of the result of each function call, and passing
it to the next one.

In other words, reduce!fn(a, range) is like doing this:

fn(range[5], fn(range[4], fn(range[3], fn(range[2], fn(range[1],
fn(range[0], a))))));

What you want is probably uniq:

http://dlang.org/library/std/algorithm/uniq.html

Note that it works on a SORTED range, so you want to sort first.

Note also that what it returns is not an array, but a lazily iterated
range over the array. If you want another array, this is the code I would
use:

arr.sort();
arr = arr.uniq.array();

-Steve
```
Apr 18 2014
"monarch_dodra" <monarchdodra gmail.com> writes:
```On Friday, 18 April 2014 at 20:27:20 UTC, Steven Schveighoffer
wrote:
Note also that what it returns is not an array, but a lazily
iterated range over the array. If you want another array, this
is the code I would use:

arr.sort();
arr = arr.uniq.array();

-Steve

Out of curiosity, if the requirement was to *also* preserve
ordering (eg: remove all non-first elements), how would you go at
it?

[2, 1, 1, 3, 2, 3] => [2, 1, 3];

Maybe std.algorithm's `makeIndex` would help here?

Bonus points for doing it inplace.
```
Apr 18 2014
"bearophile" <bearophileHUGS lycos.com> writes:
```monarch_dodra:

Out of curiosity, if the requirement was to *also* preserve
ordering (eg: remove all non-first elements), how would you go
at it?

[2, 1, 1, 3, 2, 3] => [2, 1, 3];

Maybe std.algorithm's `makeIndex` would help here?

Bonus points for doing it inplace.

This preserves ordering and it's in-place. Not tested much:

void main() {
import std.stdio, std.traits;

auto data = [2, 1, 1, 3, 2, 3];

bool[ForeachType!(typeof(data))] seen;
size_t pos = 0;
foreach (immutable i; 0 .. data.length)
if (data[i] !in seen) {
if (pos != i)
data[pos] = data[i];
seen[data[i]] = true;
pos++;
}
data.length = pos;

data.writeln;
}

Bye,
bearophile
```
Apr 18 2014
"monarch_dodra" <monarchdodra gmail.com> writes:
```On Friday, 18 April 2014 at 22:11:17 UTC, bearophile wrote:
monarch_dodra:

Out of curiosity, if the requirement was to *also* preserve
ordering (eg: remove all non-first elements), how would you go
at it?

[2, 1, 1, 3, 2, 3] => [2, 1, 3];

Maybe std.algorithm's `makeIndex` would help here?

Bonus points for doing it inplace.

This preserves ordering and it's in-place. Not tested much:

void main() {
import std.stdio, std.traits;

auto data = [2, 1, 1, 3, 2, 3];

bool[ForeachType!(typeof(data))] seen;
size_t pos = 0;
foreach (immutable i; 0 .. data.length)
if (data[i] !in seen) {
if (pos != i)
data[pos] = data[i];
seen[data[i]] = true;
pos++;
}
data.length = pos;

data.writeln;
}

Bye,
bearophile

I thought of an approach somewhere along these lines. I was
wondering if there was a UFCS approach too. Or an in-place
approach.

Well, the "inplace" is easy of you accept N² performance :)
```
Apr 19 2014
"monarch_dodra" <monarchdodra gmail.com> writes:
```On Friday, 18 April 2014 at 22:11:17 UTC, bearophile wrote:
This preserves ordering and it's in-place. Not tested much:

void main() {
import std.stdio, std.traits;

auto data = [2, 1, 1, 3, 2, 3];

bool[ForeachType!(typeof(data))] seen;
size_t pos = 0;
foreach (immutable i; 0 .. data.length)
if (data[i] !in seen) {
if (pos != i)
data[pos] = data[i];
seen[data[i]] = true;
pos++;
}
data.length = pos;

data.writeln;
}

Bye,
bearophile

If you replace that "=" with a swap, then you can also preserve
the duplicate elements at the end (although in no specific
ordering):

import std.stdio : writefln;
import std.algorithm : canFind, swap;

//----
void main()
{
auto arr = [1,1,5,2,3,2,2,4,5,5,1];
size_t pos = 0;
foreach(ref e; arr)
if (!arr[0 .. pos].canFind(e))
swap(arr[pos++], e);
writefln("uniques: %s", arr[0 .. pos]);
writefln("dupes:   %s", arr[pos .. \$]);
}
//----

I was trying a "100% inplace" solution, but I found nothing
better than N². It's  basically still what you submitted though.
```
Apr 19 2014
Tim Holzschuh via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
```Am 18.04.2014 22:27, schrieb Steven Schveighoffer via Digitalmars-d-learn:
arr.sort();
arr = arr.uniq.array();

-Steve

Thanks, also for the explanation!
- Tim
```
Apr 19 2014
"MattCoder" <idonthaveany mail.com> writes:
```On Friday, 18 April 2014 at 20:02:41 UTC, Tim Holzschuh via
Digitalmars-d-learn wrote:
Hi there,

I try to remove all equal elements of an array, thus [2,2] -->
[2].

I thought this maybe would be possible with
std.algorithm.reduce, but at least the way I tried it doesn't
work:

arr.reduce( (a,b) => a != b );

Is there a simple solution using Phobos-functions?

Not too fancy, since I'm new in D, but I created this:

import std.stdio;
import std.array;
import std.algorithm;

static if (!is(typeof(writeln)))
alias writefln writeln;

void main(){
int myfilter(int a){
static int[] b;
if(b.find(a) == []){
b.insertInPlace(b.length, a);
return a;
}
return -1;
}

auto arr = [1,1,2,3,2,2,4,5,5,1];
auto arrFiltered = arr.filter!(a => myfilter(a) > 0);

writeln(arrFiltered);
}

Tested: http://dpaste.dzfl.pl/97a1307c7fec

I'm looking for creating something like C# "extensions", maybe
with alias. I'll try later!

Matheus.
```
Apr 19 2014
=?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
```On 04/19/2014 09:55 AM, MattCoder wrote:

On Friday, 18 April 2014 at 20:02:41 UTC, Tim Holzschuh via
Digitalmars-d-learn wrote:
void main(){
int myfilter(int a){
static int[] b;

That static variable makes this solution non-reentrant. To see an effect
of this, replace the arrFiltered line with the following:

import std.range;
auto arr2 = [1,1,5,2,3];
auto arrFiltered = zip(arr.filter!(a => myfilter(a) > 0),
arr2.filter!(a => myfilter(a) > 0));

Now the two filter operations get in each other's way and the output
becomes:

[Tuple!(int, int)(1, 5), Tuple!(int, int)(2, 3)]

I wonder what happened to 4. (?) :)

if(b.find(a) == []){

There is a more explicit way of saying that:

if(!b.canFind(a)){

Ali
```
Apr 19 2014
"MattCoder" <idonthaveany mail.com> writes:
```On Saturday, 19 April 2014 at 17:12:10 UTC, Ali Çehreli wrote:
On 04/19/2014 09:55 AM, MattCoder wrote:

On Friday, 18 April 2014 at 20:02:41 UTC, Tim Holzschuh via
Digitalmars-d-learn wrote:
void main(){
int myfilter(int a){
static int[] b;

That static variable makes this solution non-reentrant...

Yes, you're completely right and I already knew that. But
remember Like I said previously, I would like to convert that
code to something close to "extensions" in C#, in that case I can
take the address of the array to check if it's a new Filter or
not. for example, current in D I can do this:

import std.stdio;
import std.array;
import std.range;
import std.algorithm;

void main(){
static int[] b;

b.clear();
}

if(!b.canFind(a)){
b.insertInPlace(b.length, a);
return a;
}
return -1;
}

auto arr  = [1,1,2,3,2,2,4,5,5,1];
auto arr2 = [3,4,3,9,9,7,4,4,4,7];

auto arrFiltered = arr.filter!(a => myfilter(&arr, a) >= 0);
writeln(arrFiltered);

auto arrFiltered2 = arr2.filter!(a => myfilter(&arr2, a) >= 0);
writeln(arrFiltered2);
}

But with extensions, the argument "address" (i.e: &arr) on the
calling of myfilter can be avoided!

Matheus.
```
Apr 19 2014