stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

`list.count` and `iterator.count`

Open apainintheneck opened this issue 1 year ago • 8 comments

This would function like Array#count does when it takes a block in Ruby.

irb(main):001:0> list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> list.count { |x| x.odd? }
=> 5

In Gleam, this can obviously be hand-coded in a few different ways but this seems like something that happens often enough that it'd be nice to have a standard library function for it.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|> list.count(int.is_odd)
fn count(list: List(a), predicate: fn(a) -> Bool) -> Int

apainintheneck avatar May 16 '24 07:05 apainintheneck

I'd assume this does what list.length does.

inoas avatar May 17 '24 11:05 inoas

Good point, maybe count_if would be a better name than count.

apainintheneck avatar May 18 '24 07:05 apainintheneck

We don't ever use suffixes like _if. Count is fine, the types make it clearer.

lpil avatar May 18 '24 13:05 lpil

I'm moving the discussion in the PR here.

@lpil is debating whether iterator.count is necessary, since the functionality is easily replicated by

iter |> iterator.filter(f) |> iterator.length

For list.count there is a performance benefit, since it can be calculated with a single iteration using the more complex/general-purpose fold (as opposed to list.filter(f) |> list.length which requires two iterations), so list.count has more value.

However, I'm suggesting that there is also value in having the same functions available for iterator and list when possible, since users will become familiar with list.count, and it missing in iterator is a minor, confusing discrepancy.

I'll align the PR when a decision is reached 😄

thorhj avatar May 24 '24 09:05 thorhj

Just my 2 cents, but I agree that the consistency of having both list.count and iterator.count outweighs the fact that iterator.count isn't necessary from a performance perspective.

chuckwondo avatar May 24 '24 10:05 chuckwondo

We don't aim to make the modules have the same API, rather we try and make it so the functions match if it makes sense for them both to have a function. If in future there is a clear need for the function then we can add it, but so far I've not had anyone ask for it. Just list please.

lpil avatar May 24 '24 15:05 lpil

I mentioned iterator.count at the beginning without realizing that iter |> iterator.filter(f) |> iterator.length was equivalent from a performance perspective and assuming that consistency was desired. Not including it makes sense to me now.

apainintheneck avatar May 24 '24 16:05 apainintheneck

Copy that, I have removed iterator.count from the PR now 🔥

thorhj avatar May 24 '24 19:05 thorhj

This function might be useful also for dict and set. Please have a look at the related PR: https://github.com/gleam-lang/stdlib/pull/617.

Thanks!

ustitc avatar May 29 '24 22:05 ustitc

Maybe! Has it come up much in your code? What were you doing when it did? Thank you.

lpil avatar May 30 '24 09:05 lpil

🤔 I see your point.

I don't have any practical case for those functions; my motivation was driven by consistency. I aimed to create similar functions for all data structures.

And I totally missed your earlier message in this thread about prioritising need over consistency. I'll cancel the PR. Thanks for the feedback!

ustitc avatar May 30 '24 21:05 ustitc

Closing as this already got implemented by @thorhj!

  • https://github.com/gleam-lang/stdlib/pull/601

apainintheneck avatar May 31 '24 06:05 apainintheneck