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

Proposal: std/collections - first part #993

Merged
merged 58 commits into from
Jul 15, 2021
Merged

Conversation

kt3k
Copy link
Member

@kt3k kt3k commented Jun 30, 2021

This proposal suggests adding 17 APIs (11 Array utils, 6 Record utils) as std/collections module. (These are extracted from the original proposal #978 by @LionC. We keep discussion on other APIs on the original PR.)

Array utils (11)

  • distinct
  • distinctBy
  • intersect
  • union
  • findLast
  • zip
  • unzip
  • groupBy
  • partition
  • chunked
  • permutations

Record utils (6)

  • filterEntries
  • filterKeys
  • filterValues
  • mapEntries
  • mapKeys
  • mapValues

In the original issue, nobody was against adding these 17. So this can be a minimal set of APIs which we could land as a first pass of std/collections.

I'd like to land these items first if there's no strong objections to some specific items or the addition of std/collections entirely.

@ry ry requested a review from wperron July 1, 2021 23:14
@LionC LionC force-pushed the std-collections-part1 branch 2 times, most recently from 962800c to b0f1047 Compare July 2, 2021 00:37
wperron and others added 3 commits July 2, 2021 16:42
Adds test cases for the `union function. Also applied formatting on the
directory, also refactored existing test cases to use the same
convention on naming tests etc.

Adds the copyright headers to all files in the module.
Copy link
Member

@ry ry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a good set of APIs to start with.

@wperron
Copy link
Contributor

wperron commented Jul 7, 2021

I started implementing union and intersect one think I'm noticing is that we could change the input parameters from a: Array<T>, b: Array<T> to ...a: Array<Array<T>> so that it can be called on an arbitrary number of arrays at once.

collections/union.ts Outdated Show resolved Hide resolved
@LionC
Copy link
Contributor

LionC commented Jul 9, 2021

I like the varargs for union and intersect.

I am back from vacation now and will continue implementing :-)

* const numbers = [ 3, 2, 5, 2, 5 ]
* const distinctNumbers = distinct(numbers)
*
* console.assert(distinctNumbers === [ 3, 2, 5 ])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: console.assert will always fail because their identities are different. assert.deepStrictEqual(distinctNumbers, [3,2,5]) in nodejs or expect(distinctNumbers).toEqual([3,2,5]) in jest might be a better choice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right - we should make sure that those examples actually work. I just totally missed that. I will put it on my to do list to do a sweep of that in the end.

@LionC
Copy link
Contributor

LionC commented Jul 14, 2021

I am finished with implementations and tests for now - obviously pending review. Will move on to refining types and docs now.

@sebastienfilion
Copy link

Amazing work!

I was wondering if there’d be a lot of opposition to sticking to intransitive verbs for the functions. I am confused by chunked and permutations — why isn’t it chunk and permute?
Those two specifically led me off their true intent.

Then there’s union which definitely is more common… although it could be named concat, or concatUnique since it seems to remove duplicates… but I don’t have a strong opinion about that last one.

@LionC
Copy link
Contributor

LionC commented Jul 14, 2021

I was wondering if there’d be a lot of opposition to sticking to intransitive verbs for the functions. I am confused by chunked and permutations — why isn’t it chunk and permute?
Those two specifically led me off their true intent.

Then there’s union which definitely is more common… although it could be named concat, or concatUnique since it seems to remove duplicates… but I don’t have a strong opinion about that last one.

To be honest, names are mostly stolen from kotlin/collections and lodash, which seem to have a very similiar idea about this. As they are both used a lot and I personally never had an issue with the names, I did not modify them too much.

@getspooky
Copy link
Contributor

Amazing work 👍,
I think it would be helpful to add this collections of 17 APIs (11 Array utils, 6 Record utils) into Third Party Modules
GitHub
instead of Standard Library because it's not related to deno but to typescript.

@LionC
Copy link
Contributor

LionC commented Jul 14, 2021

Amazing work 👍,

I think it would be helpful to add this collections of 17 APIs (11 Array utils, 6 Record utils) into [Third Party Modules

GitHub](https://deno.land/x) instead of Standard Library because it's not related to deno but to typescript.

As I understand it, the std lib tries to battle the dependency madness of needing third party code for everything, which is why we decided to do it this way. There has been a lot of discussion around this module on Discord and in the linked Discussions (following the links in the initial post of this PR).

Copy link
Contributor

@wperron wperron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some comments, most of them are minor nitpick, and obviously there needs to be some more docs. Also make sure that the block comments are formatted to stick within 80 characters and fix the linting errors.

Other than that, great work, looking forward to landing this!

});

Deno.test({
name: "[collections/distinctBy] gets head on noop selector",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one feels a bit weird to me; If there are no conditions on which to identify distinct item, how do we determine that they are all equivalent? Shouldn't this return a copy of the initial array instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As () => {} is equivalent to it => undefined here, it would feel like unexpected magic behavior to me if it would explicitly ignore equality (distinctity? is that a word?) for undefined. What about null? ""? What if undefined is a legit value in my model?

I wrote those tests before implementing the function, so to mee it seemed like the intuitive behavior to just distinct all values by their produced value - no matter what it is.

collections/distinct_by_test.ts Outdated Show resolved Hide resolved
export function distinct<T>(array: Array<T>): Array<T> {
const set = new Set(array);

return Array.from(set);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be inlined to return Array.from(new Set(array));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"b": "foo",
"C": 5,
"d": -2,
"": false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a case here where the same letter appears in both upper and lower would drive the point home a little better, otherwise nice test

Copy link
Contributor

@LionC LionC Jul 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - I cannot add it on vacation, feel free to do it or I will do it once I return :-)

const ret: Record<string, T> = {};
const entries = Object.entries(record);

for (const [key, value] of entries) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could inline to for (const [key, value] of Object.entries(record)) {

collections/map_entries.ts Show resolved Hide resolved
collections/map_keys.ts Show resolved Hide resolved
collections/map_values.ts Show resolved Hide resolved
collections/unzip.ts Show resolved Hide resolved
collections/_utils.ts Show resolved Hide resolved
Copy link
Member

@ry ry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thank you @LionC !

Good enough for a first pass, we can clean up in the future as necessary

@ry ry merged commit a23eb70 into denoland:main Jul 15, 2021
@ry ry mentioned this pull request Jul 15, 2021
5 tasks
@kt3k kt3k deleted the std-collections-part1 branch July 16, 2021 01:21
@kt3k kt3k mentioned this pull request Jul 27, 2021
26 tasks
ry pushed a commit that referenced this pull request Jul 30, 2021
Co-authored-by: William Perron <hey@wperron.io>
ry pushed a commit that referenced this pull request Jul 30, 2021
Co-authored-by: William Perron <hey@wperron.io>
@LionC LionC mentioned this pull request Aug 27, 2021
44 tasks
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

Successfully merging this pull request may close these issues.

None yet

8 participants