ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: wishdev@gmail.com
To: ruby-core@ruby-lang.org
Subject: [ruby-core:96440] [Ruby master Feature#16446] Enumerable#take_*, Enumerable#drop_* counterparts with positive conditions
Date: Mon, 23 Dec 2019 20:29:29 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-83364.20191223202929.0cca1b1576221472@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-16446.20191223082605@ruby-lang.org

Issue #16446 has been updated by wishdev (John Higgins).


The answer here is simplicity (declarative) as opposed to wordsmithing.

We need to add an drop_until and take_until to handle 5-8 and drop_while and take_while handle 1-4

All 4 methods get a new parameter "bucket" which determines where the element that triggers the split gets placed :left or :right bucket

Your table looks something like this to me - I apologize but I prefer simpler examples

ary = [-1, 0, 1]


`ary.take_while{ |x| x.nonzero? } # => [-1]`
`ary.take_while(:right){ |x| x.nonzero? } # => [-1]`
`ary.take_while(:left){ |x| x.nonzero? } # => [-1, 0]`

`ary.drop_while{ |x| x.nonzero? } # => [0, 1]`
`ary.drop_while(:right){ |x| x.nonzero? } # => [0, 1]`
`ary.drop_while(:left){ |x| x.nonzero? } # => [1]`

`ary.take_until{ |x| x.zero? } # => [-1]`
`ary.take_until(:right){ |x| x.zero? } # => [-1]`
`ary.take_until(:left){ |x| x.zero? } # => [-1, 0]`

`ary,drop_until{ |x| x.zero? } # => [0, 1]`
`ary,drop_until(:right){ |x| x.zero? } # => [0, 1]`
`ary.drop_until(:left){ |x| x.zero? } # => [1]`

#take_* gets the left bucket and #drop_* gets the right bucket - the default would be to place the trigger in the right bucket (take_while and drop_while current behave with :right as their option in this scenario).

John

----------------------------------------
Feature #16446: Enumerable#take_*, Enumerable#drop_* counterparts with positive conditions
https://bugs.ruby-lang.org/issues/16446#change-83364

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
#16441 led me to think about the issue more generally. When we want to split a series of iterations by the first element that satisfies (or dissatisfies) a condition, we have three factors to consider.

(1) Whether we want the condition to work **negatively** or **positively**
(2) Whether we want the first element to satisfy (or dissatisfy) the condition to be included in the **left** side or the **right** side of the split
(3) Whether we want the **left** side or the **right** side in the returned output

This leads us to eight possible combinations to consider.

```ruby
enum = [1, 1, 0, 3, 3, 0, 5, 5].to_enum
```

| |(1)|(2)|(3)|method|example|
|--|--|--|--|--|--|
|1|negatively|left|left|`take_while`|`enum.foo1(&:nonzero?) # => [1, 1]`|
|2|negatively|left|right|`drop_while`|`enum.foo2(&:nonzero?) # => [0, 3, 3, 0, 5, 5]`|
|3|negatively|right|left||`enum.foo3(&:nonzero?) # => [1, 1, 0]`|
|4|negatively|right|right||`enum.foo4(&:nonzero?) # => [3, 3, 0, 5, 5]`|
|5|positively|left|left||`enum.foo5(&:zero?) # => [1, 1]`|
|6|positively|left|right||`enum.foo6(&:zero?) # => [0, 3, 3, 0, 5, 5]`|
|7|positively|right|left||`enum.foo7(&:zero?) # => [1, 1, 0]`|
|8|positively|right|right||`enum.foo8(&:zero?) # => [3, 3, 0, 5, 5]`|

Proposal #16441 asks for a method that corresponds to case 3 in the table above, but I think that would make the paradigm messy unless case 4 is also implemented. Either cases 3 and 4 should both be implemented, or both not. Actually, the current proposal is not about cases 3 and 4. I would leave that to #16641.

In many use cases (including the first example in #16641), we want to detect the "marker element" by which we split the iterations. In the cases above, that can be the element `0`. In such use cases, it is more natural to describe the condition in positive terms (i.e., `zero?`) rather than negative terms (i.e., `nonzero?`). (And in other use cases, it might be the other way around.) So I would like to propose methods that correspond to cases 5, 6, 7, 8 above.

Naming of the methods should be done systematically. As a candidate, I came up with the following:

||method|
|--|--|
|5|`take_before`|
|6|`drop_before`|
|7|`take_upto`|
|8|`drop_upto`|




-- 
https://bugs.ruby-lang.org/

  parent reply	other threads:[~2019-12-23 20:29 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <redmine.issue-16446.20191223082605@ruby-lang.org>
2019-12-23  8:26 ` [ruby-core:96419] [Ruby master Feature#16446] Enumerable#take_*, Enumerable#drop_* counterparts with positive conditions sawadatsuyoshi
2019-12-23 15:14 ` [ruby-core:96434] " shevegen
2019-12-23 20:29 ` wishdev [this message]
2019-12-23 21:52 ` [ruby-core:96442] " sawadatsuyoshi
2019-12-23 22:12 ` [ruby-core:96443] " wishdev
2019-12-27 20:43 ` [ruby-core:96526] " daniel
2019-12-28 17:59 ` [ruby-core:96558] " sawadatsuyoshi
2020-01-16  6:56 ` [ruby-core:96893] " matz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-83364.20191223202929.0cca1b1576221472@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).