Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combination for zero sized array #380

Closed
wants to merge 5 commits into from
Closed

Combination for zero sized array #380

wants to merge 5 commits into from

Conversation

leeopop
Copy link

@leeopop leeopop commented Nov 5, 2019

Fixes #361

  1. Add corner case handling for combinations
  2. Add test cases for combinations, combinations_with_replacement, and permutations.

Zero-sized array is property handled in other combinatorics operators.

1. Add corner case handler for combination
2. Add test cases for both combination and combination_with_replacement
Comment on lines 632 to 636
// Zero size on empty pool
it::assert_equal(
(0..0).combinations_with_replacement(0),
<Vec<Vec<_>>>::new(),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong. The empty vector is a valid combination of zero elements in 0..0, so (0..0).combinations_with_replacement(0) should be vec![vec![]] (like (0..0).combinations(0) and (0..0).permutations(0)), not <Vec<Vec<_>>>::new() == vec![].

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andersk

It seems that the original test cases of combinations_with_replacement has the same test cases, and I just made a copy of it.
Should fixing combinations_with_replacement and its test cases be included in this PR or should I make a separate PR?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that python itertools implementation shows value 1 (single empty set) for following inputs.

>>> len(list(itertools.combinations_with_replacement([], 0)))
1
>>> len(list(itertools.combinations([], 0)))
1
>>>

Copy link
Author

@leeopop leeopop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andersk I just added a commit that fixes combinations_with_replacement dealing with zeros.

);
// Empty pool
it::assert_equal(
(0..0).combinations_with_replacement(2),
<Vec<Vec<_>>>::new(),
vec![vec![]],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this is wrong. vec![] is only a valid combination of length 0; it’s not a valid combination of length 2.

@leeopop
Copy link
Author

leeopop commented Nov 12, 2019

@andersk Fixed here!

@andersk
Copy link
Contributor

andersk commented Nov 12, 2019

Here’s a simpler patch (against master) that achieves the correct results by removing special cases instead of by adding them:

--- a/src/combinations.rs
+++ b/src/combinations.rs
@@ -51,13 +51,11 @@ impl<I> Iterator for Combinations<I>
     type Item = Vec<I::Item>;
     fn next(&mut self) -> Option<Self::Item> {
         let mut pool_len = self.pool.len();
-        if self.pool.is_done() {
-            if pool_len == 0 || self.k > pool_len {
-                return None;
-            }
-        }
 
         if self.first {
+            if self.pool.is_done() && self.k > pool_len {
+                return None;
+            }
             self.first = false;
         } else if self.k == 0 {
             return None;
--- a/src/combinations_with_replacement.rs
+++ b/src/combinations_with_replacement.rs
@@ -66,7 +66,7 @@ where
         // If this is the first iteration, return early
         if self.first {
             // In empty edge cases, stop iterating immediately
-            return if self.k == 0 || self.pool.is_done() {
+            return if self.pool.is_done() && self.k != 0 {
                 None
             // Otherwise, yield the initial state
             } else {

Actually, now that I’m looking at the code harder, I think there are other existing bugs…

@andersk
Copy link
Contributor

andersk commented Nov 12, 2019

I opened #383 which fixes this while simplifying the code even further.

@leeopop
Copy link
Author

leeopop commented Nov 12, 2019

@andersk Yep, my PR was very rough as I'm not used to the internal implementation.
If you don't mind, you may close this PR and move to the new PR.

@andersk
Copy link
Contributor

andersk commented Nov 12, 2019

Thanks for inspiring me to take a closer look. (But I’m just a contributor like you; I don’t have any special permission to close PRs.)

@leeopop
Copy link
Author

leeopop commented Nov 12, 2019

moved to #383

@leeopop leeopop closed this Nov 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Combination on zero-sized array
2 participants