(Spun off from SE-0203 — Rename Sequence.elementsEqual - #69 by Ben_Cohen)
The way that zip(_:_:)
works currently is to take pairs of elements from its two Sequence
parameters (until one of these runs out) and provide a new Sequence
that provides these pairs as a tuple. Unfortunately, sometimes this isn't quite what we need: it's be great to have an operation that went through all of the elements in both Sequence
s, padding the shorter Sequence
so that it matches the length of the longer one. I'd like to kick around an idea to this end.
The first thing that we need to consider is what "padding" actually means. An option pitched previously on the list, as well as a comparable function in Python's itertools
, zip_longest, suggests using nil
as a default for padding. This does have the side effect of wrapping every element in an Optional
:
let numbers = [1, 2, 3]
let letters = ["a", "b"]
Array(zipExtendingShorterWithNil(numbers, letters))
// [(Optional(1), Optional("a")),
// (Optional(2), Optional("b")),
// (Optional(3), nil)]
Another option would be to allow for a user-definded padding value:
Array(zip(numbers, letters, paddingIfNecessaryWith: (0, "")))
// [(1, "a"), (2, "b"), (3, "")]
These can both coexist; we might even consider making their signatures match so it looks like the one that pads with nil
is a "default" of the other one (though, this is impossible in to completely emulate because their return type would differ).
Finally, we'd could also have another function that allowed for generating elements dynamically:
Array(zip(numbers, letters, paddingIfNecessaryWith: ({
return Int(arc4random())
}, {
return String(repeating: "", count: Int(arc4random())) // Don't run this, by the way
})))
// [(1, "a"), (2, "b"), (3, "")]
Regarding naming, @Ben_Cohen has mentioned that he would keeping a zip
prefix:
This has the benefit of enhancing discovery and underlining the relationship with the current zip(_:_:)
. I'm not great at naming things, but here's a couple other alternative (and pretty ugly, IMO) names, just for reference, including some that don't start with zip
:
Function that pads with nil
nilPaddedZip(_:_:)
zipExtendingWithNil(_:_:)
zipPaddingWithNil(_:_:)
zipExtendingShorterWithNil(_:_:)
zipPaddingShorterWithNil(_:_:)
Functions that allow for user-defined padding:
zip(_:_:withPadding:)
zip(_:_:extendingWith:)
zip(_:_:paddingShorterWith:)
zip(_:_:extendingShorterWith:)
zip(_:_:paddingShorterIfNecessaryWith:)
zip(_:_:extendingShorterIfNecessaryWith:)
Bikeshedding is possible here on whether we should have one 2-element tuple parameter for the user's choice in padding (as shown here), or whether we should have two separate parameters.
And one that's similar for both:
zipLonger(_:_:); zipLonger(_:_:paddingWith:)
Please suggest your own if you have one that's better!
Architecturally, we could have this zip also return a Zip2Sequence
as zip(_:_:)
does. I'll have to think more about how to implement this, but I was thinking about making some sort of PaddedSequence
that wraps around a given Sequence
and infinitely pads it with a given padding value once the wrapped Sequence
runs out. We might even want to consider exposing this publicly, since it be useful in and of itself.