We can also add Enum.count_until(enumerable, filter, n) and you can use filter = & &1 if you want to force enumeration, like there is for Enum.count/2 today.
On Fri, Dec 4, 2020 at 8:28 AM José Valim <jose.va...@dashbit.co> wrote: > That's a very good point Jayson. I think we should go with "count until > should take advantage of all optimizations and ignore side-effects”. I > believe it is fair to expect that no enumerable that implements count > actually has side-effects, exactly because of the implications of what you > said. > > On Fri, Dec 4, 2020 at 8:08 AM 'Jayson Vantuyl' via elixir-lang-core < > elixir-lang-core@googlegroups.com> wrote: > >> There are three questions I don’t think we’re considering: >> * What does it mean to “partially count” an Enumerable that implements an >> “efficient” `count/1` function? >> * If such an Enumerable has side-effects for its `reduce/3` function, >> should they be somehow still happen even though the `count/1` doesn’t >> necessarily iterate the elements? >> * If such an Enumerable returns a larger count that asked for, should we >> return the larger “technically correct” value; or the `max + 1` value? >> >> I generally like `count_until/2` because it‘s unopinionated about what >> you’re doing with the count. But the answers to the above question probably >> should be addressed and documented. >> >> I really see two ways to address the above question. Either we consider >> “count until implies actively counting” or “count until should take >> advantage of all optimizations and ignore side-effects”. >> >> My feel is that the latter is generally going to be more efficient in the >> common case but the former is less likely to create unexpected behavior >> from people who don’t know how their Enumerable is implemented. >> >> I’m inclined to favor the former. It won’t throw away efficiency that a >> custom Enumerable will implement, it’ll generally make naive code faster, >> and the rare cases where people expect side-effects is probably less >> important than either of those other benefits. >> >> Sent from my iPhone >> >> On Dec 3, 2020, at 21:18, José Valim <jose.va...@dashbit.co> wrote: >> >> >> Thanks Allen! I believe that's a good idea. >> >> I think the main insight is that we don't want a predicate function >> (at_least? more_than?). Using compare returns three states - which is >> better than two - but what if we just returned the number? After all, if I >> am interested in knowing if something has less than 10, 10, or more than >> 10, I just need to count until eleven. Returning a number seems to be more >> flexible too. Therefore, what do you think about: count_until(enum, value)? >> >> To check if less, eq, or more than 10: >> >> case Enum.count_until(count, 10 + 1) do >> 11 -> :gt >> 10 -> :eq >> _ -> :lt >> end >> >> For at least 10: >> >> Enum.count_until(count, 10) == 10 >> >> For more than 10: >> >> Enum.count_until(count, 10 + 1) > 10 >> >> Thoughts? >> >> >> On Fri, Dec 4, 2020 at 2:14 AM Zach Daniel <zachary.s.dan...@gmail.com> >> wrote: >> >>> Yep! I really like it :) >>> >>> On Thu, Dec 3, 2020 at 7:52 PM eksperimental < >>> eksperimen...@autistici.org> wrote: >>> >>>> On Thu, 3 Dec 2020 19:06:18 -0500 >>>> Allen Madsen <allen.c.mad...@gmail.com> wrote: >>>> >>>> > Enum.compare_count([], 1) #=> :lt >>>> > Enum.compare_count([1], 1) #=> :eq >>>> > Enum.compare_count([1, 2], 1) #=> :gt >>>> >>>> This is the way to go, because in one function call we can determine the >>>> course of the action, such as in >>>> >>>> case Enum.compare_count(list, n) do >>>> :lt -> ... >>>> :eq -> ... >>>> :gt -> ... >>>> end >>>> >>>> when using the predicate functions it would require at least two >>>> function calls. >>>> >>>> > >>>> > Allen Madsen >>>> > http://www.allenmadsen.com >>>> > >>>> > >>>> > On Thu, Dec 3, 2020 at 6:51 PM Zach Daniel >>>> > <zachary.s.dan...@gmail.com> wrote: >>>> > >>>> > > Well, List.count doesn’t exist yet, but either way it sounds like >>>> > > not a great idea :) I couldn’t find examples in other Lang’s, so >>>> > > maybe I’ll just throw out some other names: >>>> > > >>>> > > Enum.at_least?/2 >>>> > > >>>> > > Enum.at_most?/2 >>>> > > >>>> > > Enum.has_count?/2 >>>> > > >>>> > > On Thu, Dec 3, 2020 at 5:14 PM Michał Muskała <mic...@muskala.eu> >>>> > > wrote: >>>> > > >>>> > >> Unfortunately this can’t be done automatically since it has subtle >>>> > >> semantic differences. In particular Enum.count/1 (or length/1) not >>>> > >> only traverses the list to count its size, but also verifies it’s >>>> > >> a proper list raising an exception for improper lists. The >>>> > >> difference could be seen for value like: >>>> > >> >>>> > >> >>>> > >> >>>> > >> [1, 2, 3 | :invalid] >>>> > >> >>>> > >> >>>> > >> >>>> > >> Calling length/1 or Enum.count/1 on this raises. If compiler did >>>> > >> the optimisation you propose, for something like length(list) > 0, >>>> > >> it wouldn’t fully traverse the list and wouldn’t raise. Thus such >>>> > >> an optimisation is not possible in the general case. >>>> > >> >>>> > >> >>>> > >> >>>> > >> *From: *elixir-lang-core@googlegroups.com < >>>> > >> elixir-lang-core@googlegroups.com> >>>> > >> *Date: *Thursday, 3 December 2020 at 22:04 >>>> > >> *To: *elixir-lang-core@googlegroups.com < >>>> > >> elixir-lang-core@googlegroups.com> >>>> > >> *Subject: *Re: [elixir-core:9802] Proposal `Enum.more_than?/2` or >>>> > >> `List.more_than?/2` >>>> > >> >>>> > >> This probably off the table/unreasonable, but it also seems like >>>> > >> something that could be statically solved and people would never >>>> > >> need to know as it is just an optimization. E.g Enum.count(list) > >>>> > >> n could optimized by the compiler? Probably wouldn’t be good for >>>> > >> all Enums, since counting would be expected to enumerate them, so >>>> > >> maybe only something like List.count 🤷♂️ >>>> > >> >>>> > >> >>>> > >> >>>> > >> On Thu, Dec 3, 2020 at 1:42 PM Zach Daniel >>>> > >> <zachary.s.dan...@gmail.com> wrote: >>>> > >> >>>> > >> Another benefit to the options list would be supporting it for >>>> > >> count with a predicate, e.g Enum.count(enum, &some_predicate/1, >>>> > >> max: 4) >>>> > >> >>>> > >> >>>> > >> >>>> > >> On Thu, Dec 3, 2020 at 1:35 PM Zach Daniel >>>> > >> <zachary.s.dan...@gmail.com> wrote: >>>> > >> >>>> > >> Nothing is jumping out at me from elsewhere yet, but another >>>> > >> option might be accepting options in `Enum.count`, like >>>> > >> `Enum.count(list, max: 4)`. I’ll keep searching though. >>>> > >> >>>> > >> >>>> > >> >>>> > >> On Thu, Dec 3, 2020 at 1:31 PM Zach Daniel >>>> > >> <zachary.s.dan...@gmail.com> wrote: >>>> > >> >>>> > >> I agree on the name feeling subpar :) I’ll take a look and see if >>>> > >> I can find other examples. >>>> > >> >>>> > >> >>>> > >> >>>> > >> On Thu, Dec 3, 2020 at 12:21 PM José Valim <jose.va...@dashbit.co> >>>> > >> wrote: >>>> > >> >>>> > >> Thanks Zach! I like this idea but the proposed name, for some >>>> > >> reason, doesn't sit right with me. Is there any prior art from >>>> > >> other langs we could look at? >>>> > >> >>>> > >> >>>> > >> >>>> > >> On Thu, Dec 3, 2020 at 6:15 PM Zachary Daniel >>>> > >> <zachary.s.dan...@gmail.com> wrote: >>>> > >> >>>> > >> Counting a list, especially a large one, to know if there are >>>> > >> "more than x" or "less than x" items is inefficient. >>>> > >> >>>> > >> >>>> > >> >>>> > >> Right now I often see things like `if Enum.count(list) > 4 ...`, >>>> > >> mostly because writing a recursive `more_than?` check is tedious, >>>> > >> or doing something like `Enum.empty?(Enum.drop(list, 4))` is not >>>> > >> very expressive. >>>> > >> >>>> > >> >>>> > >> >>>> > >> I think it would be nice to have an `Enum.more_than?` that does >>>> > >> that work for you. It could also be `List.more_than?/2` if we >>>> > >> don't want it in Enum. Any thoughts? >>>> > >> >>>> > >> -- >>>> > >> You received this message because you are subscribed to the Google >>>> > >> Groups "elixir-lang-core" group. >>>> > >> To unsubscribe from this group and stop receiving emails from it, >>>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> > >> To view this discussion on the web visit >>>> > >> >>>> https://groups.google.com/d/msgid/elixir-lang-core/263d7c39-a32b-4294-93d8-40f248c9b3c8n%40googlegroups.com >>>> > >> < >>>> https://groups.google.com/d/msgid/elixir-lang-core/263d7c39-a32b-4294-93d8-40f248c9b3c8n%40googlegroups.com?utm_medium=email&utm_source=footer >>>> > >>>> > >> . >>>> > >> >>>> > >> -- >>>> > >> You received this message because you are subscribed to the Google >>>> > >> Groups "elixir-lang-core" group. >>>> > >> To unsubscribe from this group and stop receiving emails from it, >>>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> > >> To view this discussion on the web visit >>>> > >> >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX4NE1yWH1G5L_DjF18v8zejF0%2BSkb_oz%3DPiUHM8Mz1w%40mail.gmail.com >>>> > >> < >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX4NE1yWH1G5L_DjF18v8zejF0%2BSkb_oz%3DPiUHM8Mz1w%40mail.gmail.com?utm_medium=email&utm_source=footer >>>> > >>>> > >> . >>>> > >> >>>> > >> -- >>>> > >> You received this message because you are subscribed to the Google >>>> > >> Groups "elixir-lang-core" group. >>>> > >> To unsubscribe from this group and stop receiving emails from it, >>>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> > >> >>>> > >> To view this discussion on the web visit >>>> > >> >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BBGCrgbZamFs%2BeqLUis6mFQgvUHkKK1htSN5rDDWwMRQ%40mail.gmail.com >>>> > >> < >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BBGCrgbZamFs%2BeqLUis6mFQgvUHkKK1htSN5rDDWwMRQ%40mail.gmail.com?utm_medium=email&utm_source=footer >>>> > >>>> > >> . >>>> > >> >>>> > >> -- >>>> > >> You received this message because you are subscribed to the Google >>>> > >> Groups "elixir-lang-core" group. >>>> > >> To unsubscribe from this group and stop receiving emails from it, >>>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> > >> To view this discussion on the web visit >>>> > >> >>>> https://groups.google.com/d/msgid/elixir-lang-core/DB7PR07MB3899C92933992464F17898E1FAF20%40DB7PR07MB3899.eurprd07.prod.outlook.com >>>> > >> < >>>> https://groups.google.com/d/msgid/elixir-lang-core/DB7PR07MB3899C92933992464F17898E1FAF20%40DB7PR07MB3899.eurprd07.prod.outlook.com?utm_medium=email&utm_source=footer >>>> > >>>> > >> . >>>> > >> >>>> > > -- >>>> > > You received this message because you are subscribed to the Google >>>> > > Groups "elixir-lang-core" group. >>>> > > To unsubscribe from this group and stop receiving emails from it, >>>> > > send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> > > To view this discussion on the web visit >>>> > > >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BO2QESHcaL7-svOoAGqvr6hJi%3D8AHFqi-qNZdoFEMMwA%40mail.gmail.com >>>> > > < >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BO2QESHcaL7-svOoAGqvr6hJi%3D8AHFqi-qNZdoFEMMwA%40mail.gmail.com?utm_medium=email&utm_source=footer >>>> > >>>> > > . >>>> > > >>>> > >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "elixir-lang-core" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/elixir-lang-core/5fc98859.1c69fb81.3cf33.11a4SMTPIN_ADDED_MISSING%40gmr-mx.google.com >>>> . >>>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "elixir-lang-core" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0AfjLS-vef8u9EWpuQ3tHVaXXfvAF9QMu%2B9hin7WjoNQA%40mail.gmail.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0AfjLS-vef8u9EWpuQ3tHVaXXfvAF9QMu%2B9hin7WjoNQA%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-core+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LNUYuR%2BztiJ5p3viSEd-Tj6CbptUvyt9CrGigRtKjTMQ%40mail.gmail.com >> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LNUYuR%2BztiJ5p3viSEd-Tj6CbptUvyt9CrGigRtKjTMQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-core+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/1B141347-7013-4C56-BCFB-E1A1A4430422%40brex.com >> <https://groups.google.com/d/msgid/elixir-lang-core/1B141347-7013-4C56-BCFB-E1A1A4430422%40brex.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B7zkrwsD6ZnsC0TwqZnWKepEPw3RqaQXJ-6QCffp6e-Q%40mail.gmail.com.