From: "shan (Shannon Skipper)" <noreply@ruby-lang.org>
To: ruby-core@ruby-lang.org
Subject: [ruby-core:108387] [Ruby master Feature#18685] Enumerator.product: Cartesian product of enumerables
Date: Sat, 23 Apr 2022 19:26:17 +0000 (UTC) [thread overview]
Message-ID: <redmine.journal-97421.20220423192616.8@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-18685.20220408072029.8@ruby-lang.org
Issue #18685 has been updated by shan (Shannon Skipper).
It might also be nice to require at least one `enum` argument, since `Enumerator.product #=> [nil]` seems a bit odd. Here's a stab at lazy size:
``` ruby
def Enumerator.product(*enums, **nil, &block)
raise ArgumentError, 'wrong number of arguments (given 0, expected 1..)' if enums.empty?
unless block_given?
return to_enum(__method__, *enums) do
enums.reduce(1) do |acc, enum|
enum_size = enum.size
break unless enum_size
acc * enum_size
end
end
end
enums.reverse.reduce(block) do |inner, enum|
lambda do |*values|
enum.each_entry do |value|
inner.call(*values, value)
end
end
end.call
end
```
----------------------------------------
Feature #18685: Enumerator.product: Cartesian product of enumerables
https://bugs.ruby-lang.org/issues/18685#change-97421
* Author: knu (Akinori MUSHA)
* Status: Open
* Priority: Normal
* Target version: 3.2
----------------------------------------
I'd like to add a new Enumerator class method for generating the Cartesian product of given enumerators.
A product here does not mean an accumulated array of arrays, but an enumerator to enumerate all combinations.
```ruby
product = Enumerator.product(1..3, ["A", "B"])
p product.class #=> Enumerator
product.each do |i, c|
puts "#{i}-#{c}"
end
=begin output
1-A
1-B
2-A
2-B
3-A
3-B
=end
```
This can be used to reduce nested blocks and allows for iterating over an indefinite number of enumerable objects.
## Implementation notes
- It should internally use `each_entry` instead of `each` on enumerable objects to make sure to capture all yielded arguments.
- If no enumerable object is given, the block is called once with no argument.
- It should reject a keyword-style hash argument so we can add keyword arguments in the future without breaking existing code.
- Here's an example implementation:
```ruby
# call-seq:
# Enumerator.product(*enums) -> enum
# Enumerator.product(*enums) { |*args| block } -> return value of args[0].each_entry {}
def Enumerator.product(*enums, **nil, &block)
# TODO: size should be calculated if possible
return to_enum(__method__, *enums) if block.nil?
enums.reverse.reduce(block) { |inner, enum|
->(*values) {
enum.each_entry { |value|
inner.call(*values, value)
}
}
}.call()
end
```
- Not to be confused with `Enumerator.produce`. 😝
## Prior case
- Python: https://docs.python.org/3/library/itertools.html#itertools.product
--
https://bugs.ruby-lang.org/
next prev parent reply other threads:[~2022-04-23 19:26 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-08 7:20 [ruby-core:108198] [Ruby master Feature#18685] Enumerator.product: Cartesian product of enumerators knu (Akinori MUSHA)
2022-04-08 10:52 ` [ruby-core:108199] [Ruby master Feature#18685] Enumerator.product: Cartesian product of enumerables Eregon (Benoit Daloze)
2022-04-21 7:59 ` [ruby-core:108334] " matz (Yukihiro Matsumoto)
2022-04-21 8:04 ` [ruby-core:108335] " knu (Akinori MUSHA)
2022-04-21 10:37 ` [ruby-core:108346] " Eregon (Benoit Daloze)
2022-04-21 10:40 ` [ruby-core:108347] " Eregon (Benoit Daloze)
2022-04-23 19:26 ` shan (Shannon Skipper) [this message]
2022-04-24 2:36 ` [ruby-core:108388] " knu (Akinori MUSHA)
2022-04-26 7:02 ` [ruby-core:108405] " sawa (Tsuyoshi Sawada)
2022-07-29 8:29 ` [ruby-core:109362] " knu (Akinori MUSHA)
2022-11-17 6:42 ` [ruby-core:110790] " hsbt (Hiroshi SHIBATA)
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-97421.20220423192616.8@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).