0

I have created a custom prototype with which to clean up an array so as to remove duplicates and sort it. It worked and looked like this:

 // given an example array such as this.
var names = [ 'Lara', 'Lucy', 'Alexa', 'Vanessa', 'Lucy', 'Brianna', 'Sandra' ];

Array.prototype.clean_up = function(){
    var
        set = []
    ;
    this.forEach(function(item){
        if ( set.indexOf(item) === -1 ) {
            set.push(item);
        }
    });

    set.sort();

    return set;
};

My only gripe is that I have to call it like this:

names = names.clean_up();

I would prefer it if I could call it as followed, like Array.sort() (I believe this is called an in-place implementation). How could you do that?

names.clean_up();

EDIT: (Apparently, this belongs here and not in Answers)

My current solution looks as follows, but it feels a bit ineffective. I wonder if it could be done better.

Array.prototype.clean_up = function(){
    var
        set = [],
        self = this
    ;
    this.forEach(function(item){
        if ( set.indexOf(item) === -1 ) {
            set.push(item);
        }
    });

    set.sort();

     // reset and re-fill.
    while (this.length > 0) {
        this.pop();
    }

    set.forEach(function(item){
        self.push(item);
    });
};

Ineffective for one, and for the other: it has been mentioned several times that you should not modify original arrays. Why is that?

I mean, if there is a function like Array.sort() then it shows, that the language is capable of doing it, and that some implementations seem to be "okay"? Why is sort() okay but a custom function not?

WoodrowShigeru
  • 1,418
  • 1
  • 18
  • 25

1 Answers1

0

If you want to affect the array in place, you should look for duplicates and splice them from the array. Array.prototype.indexOf can be used with a second argument to search from the current element and remove dupes, e.g.

Array.prototype.clean = function (){
  // Iterate backwards over array
  this.reduceRight(function(acc, value, index, arr) {
    // If first index of value isn't current index, remove this element
    if (arr.indexOf(value) != index) arr.splice(index, 1);
  }, null);
  // Now sort
  this.sort();
  // Return for chaining
  return this;
}

var arr = 'aztatffgff'.split('');
console.log(arr.join());
console.log(arr.clean().join());

Iterating forwards over an array doesn't work because when elements are spliced, the elements are shuffled down so the next is skipped. You also can't just create an array using, say, filter because you can't assign that new array to this.

reduceRight could be replaced with a for loop.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • It's a bit hard to wrap your head around, and imo unintuitive with the `reduceRight`, but it perfectly does what I want. Thank you. Basically, using `splice` is the key (compared to my code). – WoodrowShigeru Oct 10 '17 at 16:21
  • @WoodrowShigeru—if there was a *forEachRight* I'd use that. ;-) – RobG Oct 10 '17 at 22:31