yocontra / node-linq

LINQ for node
http://wearefractal.com/
MIT License
77 stars 7 forks source link

Except() doesn't take a function #5

Closed rikkit closed 10 years ago

rikkit commented 10 years ago

Readme lists it as

.Except(arr, [fn])

but the coffeescript is just

Except: (arr) -> @Where (item) -> !(item in arr)

... which makes the function pretty useless. Anyone able to change this? (I'm using the npm in my first node project... and I don't know where to start with coffeescript :( )

yocontra commented 10 years ago

Except is supposed to take an array (AFAIK thats standard LINQ). I've fixed the readme to reflect this. I think what you are looking for is either Select or a filter of some sort. Can you show me what you're trying to do with the data in JS?

rikkit commented 10 years ago

I'd like it to work as in C# - i.e. return a list which is all the items in list 1 except those also in list 2, determined by a given comparison. The comparison is the bit I'm missing (I'm checking two lists of equivalent but not the same objects).

I think this would be the coffeescript? I don't know how to set up the testing environment to try it out though.

Except: (arr, fn) -> @Where (item) -> !(fn(item) in arr.Select(fn))
yocontra commented 10 years ago

You don't have to write it in coffee-script, I do javascript too...

So you make an array and wrap it in a LINQ object (lets say li). You want to get all items in li that are not in another LINQ object (lets say li2). Right?

var li = new LINQ([1,2,3]);
var li2 = new LINQ([3,4,5]);

var exclusive = li.Except(li2.ToArray()).toArray();

console.log(exclusive); // [1, 2]

If you are comparing objects by field you can do something like

var li = new LINQ([{name:"Todd"}, {name:"Rick"}]);
var li2 = new LINQ([{name:"Rick"}, {name: "John"}]);

var getField = function(i){
  return i.name;
};

var exclusive = li.Select(getField)
  .Except(li2.Select(getField).toArray())
  .toArray();

console.log(exclusive); // ["Todd"]
rikkit commented 10 years ago

Seeing as the repo is in coffeescript I thought I'd try and "speak the language" :)

That would work... but I would like to maintain the list of objects. With Select().Except() I would have to maintain the original list and search with the results? Like I say in C# Linq this is a bit simpler to use -

// c#
public class Q {
    public string Name {get;set;}

    public Q(string name) {
        Name = name;
    }
}

public class QComparer : IEqualityComparer<Q>
{
    public bool Equals(Q x, Q y) { 
        return x.Name == y.Name;
    }

    public int GetHashCode(Q obj) {
        return obj.GetHashCode();
    }
}

Usage:

// c#
var l1 = new List<Q>{ new Q("Todd"), new Q("Rick")};
var l2 = new List<Q>{ new Q("Rick"), new Q("John")};

var except = l1.Except(l2, new QComparer()); // { Q{ Name = "Todd"} }

Correct me if I'm wrong but I think this JS is simpler? Instead of passing an"EqualityComparer" object, we can pass a function:

// js
var li = new LINQ([{name:"Todd"}, {name:"Rick"}]);
var li2 = new LINQ([{name:"Rick"}, {name: "John"}]);

var getField = function(i){
  return i.name;
};

var exclusive = li.Except(li2, getField).toArray();

console.log(exclusive); // [{name: "Todd}]

If you can help me set up the build environment (I have node.js but haven't managed to get coffeescript compiling and mocha/ jasmine working), I can turn this into a pull request?

yocontra commented 10 years ago

Ah I see what you mean. I left out IEqualityComparer for now and I was going to add it later and replace it with functions like you said. There are a few places this needs to go. I will work on this when I get time.

As for dev env: Fork it, git clone your url, npm install in the older, then npm test

rikkit commented 10 years ago
identity = (item) -> (item) 

Except: (arr, fn = identity) -> @Where (item) -> !(fn(item) in (fn(item) for item in arr)) 

How's that? Is fn = identity the best way to set a default in CS?

yocontra commented 10 years ago

No that isn't right

rikkit commented 10 years ago

Do you mean code-style or logically?

yocontra commented 10 years ago

The identity variable needs to be named better and it shouldn't be a private variable of the class just put it at the top of the file. The ALINQ implementation needs to be on par with the LINQ one so if you add this to LINQ it needs to be added to ALINQ as well (+ tests)

There are multiple places where the IEqualityComparer needs to be added and it would be better to have it all in one commit