5
\$\begingroup\$

Today was my first day working with JavaScript and I tried to implement some Linq-like (C#) functions as extension methods.

I'm pretty new to JavaScript and wanted to ask you for checking my functions and tell me, whether they're good and really usable in productive applications. Or maybe, what I could do better. I don't know whether there is already a library for this; it's primarily for learning purposes.

Array.prototype.where = function * (predicate){
    for(var i=0; i < this.length; i++){
        if (predicate(this[i])) yield this[i];
    }
}

Array.prototype.all = function (predicate){
    for(var i=0; i < this.length; i++){
        if (!predicate(this[i])) return false;
    }
    return true;
}

Array.prototype.any = function (predicate){
    if (predicate == null) return this.length >0;
    for(var i=0; i < this.length; i++){
        if (predicate(this[i])) return true;
    }
    return false;
}

Array.prototype.select = function * (predicate){
    for(var i=0; i < this.length; i++){
        yield predicate(this[i], i);
    }
}

Array.prototype.groupby = function (predicate){
    var result = {};
    for(var i=0; i < this.length; i++){
        var key = predicate(this[i]);
        if (result[key] == null)
            result[key] = Array();
        result[key].push(this[i]);
    }
    return result;
}

Array.prototype.foreach = function (predicate){
    for(var i=0; i < this.length; i++){
        predicate(this[i]);
    }
}

Array.prototype.first_or_default = function (predicate){
    if (predicate == null){
        return this.length > 0 ? this[0] : null;
    }
    for(var i=0; i < this.length; i++){
        if (predicate(this[i]))
            return this[i];
    }
    return null;
}

Array.prototype.last_or_default = function (predicate){
    return this.reverse().first_or_default();
}

Array.prototype.count = function (predicate){
    var count = this.length;
    if (predicate == null) return count;
    for(var i=0; i < this.length; i++){
        if (!predicate(this[i])) count-=1;
    }
    return count;
}

Array.prototype.distinct = function * (predicate){
    var already_yielded = []
    var has_predicate = predicate != null;

    for(var i=0; i < this.length; i++){
        var current_element = this[i];

        if (!has_predicate){
            if (already_yielded.indexOf(current_element) >= 0) continue;
            already_yielded.push(current_element);
        }else{
            if (already_yielded.indexOf(predicate(current_element)) >= 0) continue;
            already_yielded.push(predicate(current_element));
        }
        yield current_element;
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I wrote a LINQ in Javascript library at github.com/Siderite/LInQer. I am looking for feedback on how to improve it. As for your code, it works, but it could use some optimizations. For example the groupby function reads the item in the dictionary object twice each item. Also result[key] is only incidentally equal to null, in fact it is undefined and it is more efficient to use === and compare the value and the type at the same time. Then you have functions like last or default which reverses the entire array and returns the first item instead of actually return the last item... \$\endgroup\$ Commented Jan 27, 2020 at 12:29

1 Answer 1

4
\$\begingroup\$

This might not really be an answer, but I suggest you to check out linq.js. So yes, there is already an implementation of this and you can look at the code to compare and it will help the "learning purposes" you're aiming for.

Example implementation of any :

 // Overload:function()
    // Overload:function(predicate)
    Enumerable.prototype.any = function (predicate) {
        predicate = Utils.createLambda(predicate);

        var enumerator = this.getEnumerator();
        try {
            if (arguments.length == 0) return enumerator.moveNext(); // case:function()

            while (enumerator.moveNext()) // case:function(predicate)
            {
                if (predicate(enumerator.current())) return true;
            }
            return false;
        }
        finally {
            Utils.dispose(enumerator);
        }
    };

I personally don't have the required experience in JavaScript to give you my opinion on your implementation. Good luck !

\$\endgroup\$
3
  • \$\begingroup\$ ah pretty nice. didn't know about linq.js and didn't know about that enumerator-thing. :) thanks for that post! \$\endgroup\$ Commented Jan 16, 2017 at 17:12
  • \$\begingroup\$ So for education and the hints I mark this answer as accepted. Linq.js seems to do exactly what I want to do and for reference of best practice this is the perfect answer. \$\endgroup\$ Commented Jan 16, 2017 at 22:42
  • \$\begingroup\$ Linq.js was nice find for me a while back coming from the C# world. Awesome once you get the syntax down. \$\endgroup\$ Commented Jan 19, 2017 at 23:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.