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

[Umbrella] collections APIs #1173

Closed
44 tasks done
LionC opened this issue Aug 27, 2021 · 10 comments
Closed
44 tasks done

[Umbrella] collections APIs #1173

LionC opened this issue Aug 27, 2021 · 10 comments

Comments

@LionC
Copy link
Contributor

LionC commented Aug 27, 2021

collections

This is an umbrella issue for the collections module, which has landed in std with this initial PR and a lot of new contributions since. The goal of this issue is to give an overview about functions that have alreayd been implemented, are being worked on and have not been started yet.

For more details on the idea behind the module, check out its Readme and contribution guide. For more details on the history of the module and its proposed signatures, see the original proposal PR.

If you want to implement one of the missing functions, please open a separate PR for it and keep discussion in that PR. Please read the contribution guide and make sure to keep the checklist in mind before opening your PR / marking it ready for review.

If you want to add onto or discuss the list, please do that here.

Unstarted / Suggestions

None right now

In Progress

Done

@LionC
Copy link
Contributor Author

LionC commented Aug 27, 2021

I offered @kt3k to open and maintain this so he does not have to :-) @kt3k you can close the old issue

@LionC LionC changed the title [Umbrella] collections module ToDos [Umbrella] collections ToDos Aug 27, 2021
@kt3k kt3k mentioned this issue Aug 27, 2021
26 tasks
@kt3k
Copy link
Member

kt3k commented Aug 31, 2021

Note: we sometimes drop the items from proposal when the implementation is too trivial.

This Luca's comment describes the reasoning behind it well.
#1168 (review)

@LionC
Copy link
Contributor Author

LionC commented Aug 31, 2021

Note: we sometimes drop the items from proposal when the implementation is too trivial.

This Luca's comment describes the reasoning behind it well.
#1168 (review)

I will keep them in the list striked out as seen above.

@LionC LionC changed the title [Umbrella] collections ToDos [Umbrella] collections APIs Aug 31, 2021
@LionC
Copy link
Contributor Author

LionC commented Sep 4, 2021

As we approach being pretty much API complete compared to the Kotlin package that inspired this (and removing the ones that we have deemed not fitting for JS right now), I would like to propose three last functions to complete the modules API for now. All three are taken mostly directly from kotlin/std/collections and lodash.

Comments welcome, I will add them to the list above soon :-)

associateWith

/**
* Builds a new Record using the given array as keys and choosing a value for each
* key using the given selector.
*/
export function associateWith<T>(array: readonly string[], selector: (key: string) => T): Record<string, T>

Missing sister function to the already implemented associateBy, used if you have an array of keys that you need to transform to a record.

joinToString

export type JoinToStringOptions = { separator?: string, prefix?: string, suffix?: string }
/**
* Transforms the elements in the given array to strings using the given selector. Joins
* the produced strings into one using the given separator and applying the given prefix
* and suffix to the whole string afterwards. Returns the resulting string.
*/
export function joinToString<T>(
    array: readonly T[],
    selector: (el: T) => string,
    {
        separator = ", ",
        prefix = "",
        suffix = "",
    }: JoinToStringOptions = {},
): string

This is straight up a more efficient version of use cases around .map().join() chains (and some postprocessing). I talked briefly about this on Discord before and some though it to bee too specific, but in my experience this happens quite a lot (.join() follows .map() more often than not in boring business applications) and we even have four .map().join() calls in non-test code in std itself (in std/http among others).

This also adds convenience to the process by allowing for an optional prefix or suffix. Kotlin also adds the option to truncate by only iterating an optional set number of elements before stopping and adding an optional truncation string. Seemed specific to me, but they also reject things they think to be too narrow, so I am unsure. Input would be welcome.

sample

/**
* Selects an element randomly from the given array and returns it.
*/
export function sample<T>(array: readonly T[]): T | undefined

Useful for all kinds of random cases like random quotes, websites, task distribution logic etc. Even though we have an (in-place) shuffle function in JS, there is no way to just get a random element. Shuffling to get one is really inefficient and the probably correct way to do it with Math.random is something people need to look up and get wrong with off-by-one errors all the time.

@LionC
Copy link
Contributor Author

LionC commented Sep 6, 2021

I added the above functions to the list and will shamelessly ping the recent contributors to the module, maybe someone wants do implement one of them :-) CC @grian32 @majidsajadi @ayame113 @getspooky

@getspooky
Copy link
Contributor

@LionC good , i will look into associateWith function.

@majidsajadi
Copy link
Contributor

so I take sample and joinToString. @LionC @getspooky

@getspooky
Copy link
Contributor

getspooky commented Sep 8, 2021

@LionC can you please confirm this example:

const users = [
   { id: 'a2e', userName: 'Anna' },
   { id: '5f8', userName: 'Arnold' },
   { id: 'd2c', userName: 'Kim' },
]
const usersByLength = associateWith(users, it => it.userName.length)
assertEquals(usersByLength, {
  '4': { id: 'a2e', userName: 'Anna' },
  '6': { id: '5f8', userName: 'Arnold' },
  '3': { id: 'd2c', userName: 'Kim' },
})

@LionC
Copy link
Contributor Author

LionC commented Sep 8, 2021

@LionC can you please confirm this example:

const users = [
   { id: 'a2e', userName: 'Anna' },
   { id: '5f8', userName: 'Arnold' },
   { id: 'd2c', userName: 'Kim' },
]
const usersByLength = associateWith(users, it => it.userName.length)
assertEquals(usersByLength, {
  '4': { id: 'a2e', userName: 'Anna' },
  '6': { id: '5f8', userName: 'Arnold' },
  '3': { id: 'd2c', userName: 'Kim' },
})

That is associateBy - we already have that in the module :-)

A correct example would be:

const names = [ 'Kim', 'Lara', 'Jonathan' ]
const namesToLength = associateWith(names, it => it.length)

assertEquals(namesToLength, {
    'Kim': 3,
    'Lara': 4,
    'Jonathan': 8,
})

@bartlomieju
Copy link
Member

@LionC great work on seeing this proposal through in full! Also thanks to @getspooky, @majidsajadi, @grian32, @ayame113 and other contributors for help implementing all the APIs. This module is a very valuable addition to the standard library!

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

5 participants