Closed gissuebot closed 10 years ago
Original comment posted by finnw1 on 2010-02-03 at 09:37 AM
I would put it in Ints/Longs rather than Iterables/Iterators.
Original comment posted by j...@nwsnet.de on 2010-02-08 at 09:34 AM
Suppliers.count()
(returning an instance of Supplier<Integer>
and/or
Supplier<Long>
; maybe the latter would be sufficient?) might be a conceivable place
for it, too.
Original comment posted by kevinb@google.com on 2010-02-12 at 05:08 PM
This is one of the things our forthcoming Range stuff will support. There may still be value in a "shortcut" method like this in Itera*s, but we'll see at the time, and it wouldn't be called "count" (since I expected that to mean "count the number of elements left in the iteration).
Original comment posted by j...@nwsnet.de on 2010-02-14 at 05:23 PM
As long as these ranges are Iterable
s (and are lazy) and support an "open end",
I'll be fine.
Original comment posted by j...@nwsnet.de on 2010-08-18 at 01:08 PM
Any news regarding the promised Range stuff?
Original comment posted by boppenheim@google.com on 2010-12-30 at 01:21 AM
Issue #506 has been merged into this issue.
Original comment posted by boppenheim@google.com on 2010-12-30 at 01:22 AM
(No comment entered for this change.)
Original comment posted by fry@google.com on 2011-01-26 at 10:40 PM
(No comment entered for this change.)
Status: Accepted
Labels: Type-Enhancement
Original comment posted by kevinb@google.com on 2011-01-27 at 06:16 AM
(No comment entered for this change.)
Status: Started
Original comment posted by kevinb@google.com on 2011-01-27 at 06:17 AM
Issue #429 has been merged into this issue.
Original comment posted by j...@nwsnet.de on 2011-03-31 at 12:06 PM
Any news regarding this? Having ranges would also allow simplifying or even replacing some of those ugly for
loops.
Original comment posted by kevinb@google.com on 2011-04-08 at 02:06 AM
(No comment entered for this change.)
Labels: Milestone-Release10
Original comment posted by kevinb@google.com on 2011-05-03 at 10:48 PM
(No comment entered for this change.)
Status: Fixed
Original comment posted by j...@nwsnet.de on 2011-05-05 at 12:46 PM
How is this class meant to be used? I see neither a public constructor nor a public factory method nor classes like Ints
implement methods that would yield a range.
Oh, and is apply(C)
going to be deprecated forever and right from the start because the name inherited from Predicate
is ambiguous for ranges?
Original comment posted by cgdecker on 2011-05-05 at 02:16 PM
You use the Ranges class to create Ranges. And yes, I imagine apply(C) is going to be deprecated forever because you should always use the more descriptive contains(C) when calling a method directly. Only code treating the Range as a Predicate should be using apply.
Original comment posted by kevinb@google.com on 2011-05-05 at 02:31 PM
We treat the meaning of @Deprecated as: "there is no good reason that your code should invoke this method (directly)." It's a common misconception that deprecation is only about "I'm going to delete this." Ordering.from(Ordering) is another example of a deprecated method we expect to have forever.
Original comment posted by j...@nwsnet.de on 2011-05-06 at 09:09 AM
Oh, I totally forgot about Ranges
while taking a deeper look into Ranges
and its Javadocs.
But I still can't imagine how this can be used to solve my initially (though maybe not sufficiently explicitly) described use case of iterating over ranges of numbers. I'd expect something like for (Integer x : Ranges.closed(1, 100))
to work, as a cleaner and less error-prone alternative to incrementing an int in a for
loop, and similar to Scala's 1 to 100
or Python's range(1, 101)
, for example.
Ranges.atLeast(20)
resembles my above count(20)
example, but I still need to be able to iterate over it for as long as I decide not to break the loop over it (which, as I'd expect, has to be ultimately done with open ranges anyway).
What did I miss this time? I guess it doesn't implement Iterable
or something like that for a reason, including the above one about not terminating by itself in case of (half-)open ranges.
Original comment posted by ogregoire on 2011-05-06 at 11:56 AM
Indeed, that is somehow unexpected.
It looks like the automated generation of numbers isn't supported by Range, which is the main reason why I starred the bug: a python-like range().
Current implementation of Range is interesting but much less than the initial request that yo...@nwsnet.de initially asked.
Original comment posted by neveue on 2011-05-06 at 12:17 PM
For this, you need to combine a Range with a DiscreteDomain:
for (int i : Ranges.closed(1, 100).asSet(DiscreteDomains.integers()))
Original comment posted by raymond.rishty on 2011-05-06 at 01:14 PM
@nev..., I believe the initial request was that there would be an iterator that would generate the next number on-the-fly ("in a memory-efficient way"), rather than "keep the whole range in memory".
Personally, I don't think this would be a particularly complicated thing to implement yourself, and I don't know how much it would really add for general use (though that's not my call).
Original comment posted by cgdecker on 2011-05-06 at 01:44 PM
@raymond: The ImmutableSet returned by asSet(DiscreteDomain) (note that it isn't called "toSet") does generate numbers on the fly in a memory-efficient manner.
Original comment posted by kevinb@google.com on 2011-05-06 at 11:11 PM
As you can tell from
for (int i : Ranges.closed(1, 100).asSet(DiscreteDomains.integers()))
it is clearly not a design goal of Ranges to support this use case cleanly. Why? Because even if we did the best we could to support it, it would still be better to do this:
for (int i = 1; i <= 100; i++)
Original comment posted by ogregoire on 2011-05-07 at 06:28 PM
Well, the for loop is not the only use case. Personally, I won't use that much. I really wanted Ranges to implement Iterable in order to easily create data structure of numbers that follow a simple rule, transform the lists, filter them, etc.
Looks like I'll be stuck with the ugly asSet(DiscreteDomain.integers()), which vocabulary is absolutely correct, but not understandable for the common of developers, especially non-native English speakers.
Original comment posted by j...@nwsnet.de on 2011-05-09 at 10:15 AM
Hm, bummer.
The discrete domain stuff is far too complicated for being used commonly. Also, while asSet
is returning an immutable set with a fixed iteration order, it is irritating as a reader would expect a range to return some kind of list or another iterable that is not looking as it wouldn't care about ordering.
My issue with counting for
loops is they are hard to grok in detail at a quick glance and thus easily hide off-by-one errors. ("Modern") "scripting" languages, e.g. Ruby, became really popular for a reason; clean ways to create ranges is one tiny part of the story.
I'd happily add some chars to the for
one-liner in order to gain clarity.
A counting iterator indeed is easy to implement, but it still could be used in lots of places even in smaller projects. And there are various number types this could be useful for (int, long, BigDecimal), too, which would require additional implementations. That's why I think a library should contain these.
In any case, even with the code in comment #19, I don't consider my original request fixed.
However, regarding the issue, I can imagine the addition of an IntRange
subclass which would provide such functionality. But that's just a quick thought.
Original comment posted by ted.zlatanov on 2011-05-09 at 02:20 PM
By far the most common Range->Set usage for me would be to generate an integer set. So I think it would be a nice bit of syntactic sugar to provide as asIntegerSet() method which simply uses asSet(DiscreteDomains.integers()) behind the scenes. Obviously the user can write the method themselves but this way it's explicitly provided in the direct API instead of specified by the user in an indirect way.
Also it's too bad that only continuous ranges were provided. R-trees or inversion lists would have been more generally useful.
Original comment posted by cgdecker on 2011-05-09 at 10:01 PM
Also, while
asSet
is returning an immutable set with a fixed iteration order, it is irritating as a reader would expect a range to return some kind of list or another iterable that is not looking as it wouldn't care about ordering.
It returns an ImmutableSortedSet, so the fact that it's ordered should be clear.
So I think it would be a nice bit of syntactic sugar to provide as asIntegerSet() method which simply uses asSet(DiscreteDomains.integers()) behind the scenes.
It doesn't make sense to have an asIntegerSet() method on a Range<Foo>, were it even possible.
Original comment posted by ted.zlatanov on 2011-05-10 at 01:26 AM
It doesn't make sense to have an asIntegerSet() method on a Range<Foo>, were it even possible.
I think it makes sense for any Range<Number> or at least any numbers that can be mapped on the number line (forgive my ignorance of all the Number variations in Java).
Original comment posted by cgdecker on 2011-05-10 at 02:19 AM
My point was that Range is a general-purpose class that can be used with many things that aren't numbers. In any case, I think using static imports might make this read a little more like you want: range.asSet(integers())
Original comment posted by gscerbak on 2011-05-10 at 12:08 PM
I think this issue was about creating a convenient method for iterating. The proposed Range is more about mathematical notion of intervals. I think there already is such a feature - it is the AbstractLinkedIterator. I created an Iterable around it, which takes a first value and a function for computing the next value. I added static factory method for this Iterable, which I call unfold.
Examples:
@Test
public final void numsFrom() {
assertThat(limit(unfold(5, successor), 3), hasItems(5, 6, 7));
}
@Test
public final void squares() {
final Iterable<Integer> squares = transform(unfold(0, successor),
new Function<Integer, Integer>() {
@Override
public Integer apply(final Integer input) {
return input * input;
}
});
assertThat(limit(squares, 6), hasItems(0, 1, 4, 9, 16, 25));
}
@Test
public final void primes() {
final Iterable<Integer> primes = unfold(2, new Function<Integer, Integer>() {
private Predicate<Integer> sieve = alwaysTrue();
@Override
public Integer apply(Integer input) {
while (!sieve.apply(input)) {
input++;
}
final Integer prime = input;
sieve = and(sieve, new Predicate<Integer>() {
@Override
public boolean apply(final Integer number) {
return number % prime != 0;
}
});
return prime;
}
});
assertThat(get(primes, 300), is(1987));
}
I think this might be a better temporary solution until it is clear what sort of Ranges people really want.
Original comment posted by ted.zlatanov on 2011-05-12 at 02:37 PM
Should I make a request for a NumberRange class? The specific case where the range is numeric has specific uses and optimizations that can't apply to general Ranges.
Original comment posted by gscerbak on 2011-05-12 at 02:53 PM
I don't think NumberRange is a good idea. The thing that people are asking for is Range for DiscreteDomain, especially with convenient Iterables. It looks similar to IndexedIterable, which is in the idea graveyard, but I don't know for what reasons. As AbstractLinkedIterator got into the library, it could be a viable alternative to implement something similar to such Iterable with it, as I showed above.
Original comment posted by ted.zlatanov on 2011-05-12 at 03:05 PM
OK, I'll go with that since it's so easy to use Range as a NumberRange. Thanks.
Original comment posted by g.e.dejong on 2011-06-06 at 12:50 PM
I think the ranges is an excellent addition to the library. All new language or library additions will be hard to grok at first. Anyways, I had a small question regarding ranges:
I previously implemented some utilities to handle Ranges (intervals in our system). For simplicity sake, we forced intervals to have a closed left and open right. We stumbled a bit when we wanted to decide whether an open interval contains another open interval when the bounds are equal (eg. [0, 1) and [0, 1)). As far as I know (I'm not a mathematician), this is only true when the measures of both intervals are equal, which cannot be guaranteed. Therefor, I opted to have it return false, but I was wondering why Guava decided to return true instead.
With kind regards,
Original issue created by j...@nwsnet.de on 2010-02-03 at 09:29 AM
I'd like to see a simple
count(n)
method inIterables
(and probably inIterators
, too). This would allow to easily generate a range of numbers in a memory-efficient way (i.e. without the need to keep the whole range in memory).E.g.,
count(20)
would generate the numbers 20, 21, 22, 23, and so on. A default starting value (I'd expect0
) is conceivable, though not really necessary.If there is a much better way to achieve the above and which I might have missed, please enlighten me.