Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can add a Set operate: R.isSubset ? #1914

Open
adispring opened this issue Sep 21, 2016 · 17 comments
Open

can add a Set operate: R.isSubset ? #1914

adispring opened this issue Sep 21, 2016 · 17 comments

Comments

@adispring
Copy link
Member

adispring commented Sep 21, 2016

[a] -> [b] -> Boolean
const isSubset = R.curry((subset, set) => R.equals(R.intersection(subset, set), subset));
isSubset([1, 2], [1, 2, 3])); // true
isSubset([1, 2, 3], [1, 2, 3])); // true
isSubset([1, 2, 3, 4], [1, 2, 3])); // false
@buzzdecafe
Copy link
Member

could be interesting, are you willing to do a PR? A couple of notes: I think the signature would have to be Set a -> Set a -> Boolean; and I wonder if it makes more sense to take the superset as the first argument?

@CrossEye
Copy link
Member

CrossEye commented Sep 21, 2016

I think the signature would have to be Set a -> Set a -> Boolean;

Are you suggesting the native Set type or simply lists that are assumed to have no duplicates?

If it were [a] -> [a] -> Boolean or (oddly?) [a] -> [b] -> Boolean, what would be the expectation in dealing with MultiSets/Bags, e.g.

isSubset([1, 2, 2], [1, 2, 3, 4]); //=> ??

@adispring
Copy link
Member Author

Since Array(list) is not set, isSubset should use uniq and sort, like union and intersection.

@adispring
Copy link
Member Author

adispring commented Sep 21, 2016

const isSubset = R.curry((set, subset) => {
  const sortU = R.compose(R.sort((a, b) => a - b), R.uniq);
  return R.equals(sortU(R.intersection(set, subset)), sortU(subset));
});
console.log(isSubset([1, 2], [1, 2, 3])); // true
console.log(isSubset([1, 2, 2, 2], [1, 2, 3])); // true
console.log(isSubset([1, 2, 3, 4], [1, 2, 3])); // false

list's subset looks wired.

@CrossEye
Copy link
Member

Of course not everything we might want to test for uniqueness/subset is necessarily ordered. I don't think an actual implementation could use any kind of sort.

@adispring
Copy link
Member Author

adispring commented Sep 22, 2016

another implementation:

const isSubset = R.compose(R.isEmpty, R.without);

const set = [2, 1, 3, 1, 3];
const subset = [2, 2, 2, 1, 2];
console.log(isSubset(set, subset)); // true

@buzzdecafe
Copy link
Member

I don't like using arbitrary lists as arguments to a function called isSubSet.

const set = [2, 1, 3, 1, 3]; // Not a Set
const subset = [2, 2, 2, 1, 2]; // // Not a Set
isSubset(set, subset) // should throw TypeError

Simplest would be to find a better name (isSubBag? 😜); the harder thing would be to support actual Sets (i.e. not JS Set).

@CrossEye
Copy link
Member

CrossEye commented Nov 1, 2016

...or conceivably to support something like sanctuary-js/sanctuary-set#1.

@adispring
Copy link
Member Author

OK, I will take a look at that repository to see what should I do.

@CrossEye
Copy link
Member

CrossEye commented Nov 2, 2016

That's a huge piece of work. I was really just riffing on the suggestion from @buzzdecafe. Ramda generally does not supply types. But because of our insistence on value equality, the native Set type is fairly useless to us; something like the work here might be more helpful. But it's a large undertaking, not a quick PR, I'm afraid.

@semmel
Copy link
Contributor

semmel commented May 12, 2018

@adispring R.isSubset is a very useful function because it is the generalization of R.contains i.e. R.includes nowadays.

Yet another implementation taking the subset as first argument (maybe for the Cookbook along overlaps)

var isSubset = R.compose(R.isEmpty, R.useWith(R.difference, [R.uniq, R.uniq]));
console.log(isSubset([1, 2], [1, 2, 3])); // true
console.log(isSubset([1, 2, 2, 2], [1, 2, 3])); // true
console.log(isSubset([1, 2, 3, 4], [1, 2, 3])); // false
isSubset([2, 2, 2, 1, 2], [2, 1, 3, 1, 3]); // true

@danielo515
Copy link

I pretty much prefer the implementation of @adispring . Not only it is simpler but for me it's also more useful to take the big set first.
Was this implemented? I guess no...

@crvouga
Copy link

crvouga commented May 29, 2019

const isSubset = R.curry((xs, ys) =>
	R.all(R.contains(R.__, ys), xs))

@Ruben9922
Copy link

Ruben9922 commented Feb 1, 2021

I think having an isSubset (and maybe isSuperset) function in Ramda would be a great idea, especially as Ramda already contains functions for common set operations such as union, intersection and difference. Also, I personally would be happy just having it work on lists (rather than JS Set), to be consistent with said set operations already in Ramda.

Regarding the naming, I guess an alternative name could be includesAll or containsAll (as @semmel said, it can be thought of as a generalisation of includes/contains). Though personally I prefer isSubset, again to consistent with the set operations already in Ramda (which, despite working on lists, are named after set operations).

@Ruben9922
Copy link

Ruben9922 commented Feb 1, 2021

Yet another implementation would be to check whether the union equals set:

const sortU = R.pipe(R.uniq, R.sortBy(R.identity));
const isSubset = (subset, set) => R.equals(sortU(R.union(subset, set)), sortU(set));

Another alternative would be to compare the cardinalities of the sets, rather than the sets themselves:

const isSubset = (subset, set) => R.equals(R.length(R.intersection(subset, set)), R.length(subset));

(This follows on from the first method by @adispring - checking whether intersection equals subset. Also, note that the equivalency this is based on assumes subset is finite.)

See here.

@CrossEye
Copy link
Member

CrossEye commented Feb 3, 2021

@Ruben9922:

Are you interested in submitting a PR for this?

@Ruben9922
Copy link

@CrossEye
Yeah, that would be great! I'll try to work on it over the next few days.

@adispring adispring reopened this Apr 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants