From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-2.6 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, FORGED_GMAIL_RCVD,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id BAE451F463 for ; Mon, 23 Dec 2019 20:29:40 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id DED60120AD7; Tue, 24 Dec 2019 05:29:25 +0900 (JST) Received: from xtrwkhkc.outbound-mail.sendgrid.net (xtrwkhkc.outbound-mail.sendgrid.net [167.89.16.28]) by neon.ruby-lang.org (Postfix) with ESMTPS id D7B44120AD5 for ; Tue, 24 Dec 2019 05:29:23 +0900 (JST) Received: by filterdrecv-p3mdw1-56c97568b5-9vfcv with SMTP id filterdrecv-p3mdw1-56c97568b5-9vfcv-17-5E0123A9-28 2019-12-23 20:29:29.600494995 +0000 UTC m=+589578.223057913 Received: from herokuapp.com (unknown [18.233.7.172]) by ismtpd0103p1mdw1.sendgrid.net (SG) with ESMTP id s7fojT8FTgqS9mOfZHAofA for ; Mon, 23 Dec 2019 20:29:29.532 +0000 (UTC) Date: Mon, 23 Dec 2019 20:29:29 +0000 (UTC) From: wishdev@gmail.com Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 72099 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 16446 X-Redmine-Issue-Author: sawa X-Redmine-Sender: wishdev X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: =?us-ascii?Q?Z4Ej7Bg37lK69JtZPFJ+UW67gqYKj9Iu8E0xhUBC8OXIQd0x3i8L+OzD1w0F1d?= =?us-ascii?Q?hgckA+g9VbEEJusapjgUkhMAA6Ti19DISEgMdSA?= =?us-ascii?Q?AxtGWfnPUBhbrU3xseEVbgcLLGDW9+6ZA6Pz2Gv?= =?us-ascii?Q?BFyuy5DRdMfE+VIkShzznF+4Nc+lzm4Lg+8UMIA?= =?us-ascii?Q?TcqdqcpKMox9hwww3KdL8MGWuf0anrZdSKrZb3E?= =?us-ascii?Q?t0dKPA5Kw02X3NS=2Fs=3D?= To: ruby-core@ruby-lang.org X-ML-Name: ruby-core X-Mail-Count: 96440 Subject: [ruby-core:96440] [Ruby master Feature#16446] Enumerable#take_*, Enumerable#drop_* counterparts with positive conditions X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" 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/