TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Always use [closed, open) intervals

211 点作者 smukherjee19超过 2 年前

35 条评论

rav超过 2 年前
Half-open intervals are why I try as much as possible to stay away from languages that use 1-based indexing (Lua, Julia, Matlab, R, ...) - 1-based indexing lends itself to closed intervals because an array of N elements has [1,N] as its index range, whereas 0-based indexing lends itself to half-open intervals because an array of N elements has [0,N) as its index range.<p>-------<p>However, I know of one case where closed intervals really shine. Consider displaying a zoomable map in tiles. On a given zoom level, each tile has some coordinates (x;y) where x and y are integers denoting the virtual column and row. Suppose that we allow zooming out by a factor 2, so that two-by-two tiles are aggregated into a single tile. Then a natural choice for the coordinates of the zoomed-out tile are (floor(x&#x2F;2);floor(y&#x2F;2)), that is, divide by two and round down. Suppose that a dataset has data on tile coordinates [x1,x2]×[y1,y2], meaning that there&#x27;s only data on tiles (x;y) where x1≤x≤x2 and y1≤y≤y2. These are closed intervals, but stay with me - the reason they are nice in this case is because of how you compute the range of valid tile coordinates when you zoom out: The range becomes [floor(x1&#x2F;2),floor(x2&#x2F;2)]×[floor(y1&#x2F;2),floor(y2&#x2F;2)] - that is, you simply divide the range endpoints by two and round down. If you try to do this with half-open intervals, then you need some +1&#x2F;-1 shenanigans, which are normally what I try to avoid by going for half-open intervals.
评论 #33707466 未加载
评论 #33707246 未加载
评论 #33713789 未加载
评论 #33706162 未加载
评论 #33708389 未加载
ChrisMarshallNY超过 2 年前
<i>&gt; Never, ever, ever use [closed, closed] intervals</i><p>I’m not really a fan of “never,” or “always” rules, when it comes to programming. I’ve found it’s usually better to have a “make sure to justify deviations from” heuristics.<p>I usually use [closed..open) ranges (as they are called in Swift), but sometimes, an inclusive range is a lot more appropriate, for expressing an operation <i>(for example, I may express a range as start...end, as opposed to start..&lt;(end + 1)).</i>
评论 #33706184 未加载
评论 #33708577 未加载
评论 #33704259 未加载
评论 #33705223 未加载
评论 #33706097 未加载
评论 #33707231 未加载
elcaro超过 2 年前
I&#x27;ll repeat the sentiment that &quot;always&quot; and &quot;never&quot; rules usually have their fair share of exception.<p>And while I agree that [closed, open) intervals are often the best choice... sometimes what you want is [closed, closed], or (open, open), and it&#x27;s nice to use a language that makes that easy.<p>For example, Raku makes it easy to do:<p><pre><code> [closed, closed] with ($a .. $b) [closed, open) with ($a ..^ $b) (open, open) with ($a ^..^ $b) (open, closed] with ($a ^.. $b)</code></pre>
dragontamer超过 2 年前
Ehh, this post misses the important tidbid.<p>You should keep your code consistent across your organization, so that a large number of programmers knows how your code works. You should have a &quot;default writing style&quot;, and the &quot;default writing style&quot; should be used unless you have very, very, very good reasons to avoid it. (And an errant +1 or -1 here and there isn&#x27;t a good enough reason to switch).<p>There are four styles of intervals. Lets say you want to represent a loop of 5 iterations numbered [555, 556, 557, 558, 559]. You&#x27;ve got:<p>* [closed, closed] -- [555, 559]<p>* [closed, open&gt; -- [555, 560&gt;<p>* &lt;open, closed] -- &lt;554, 559]<p>* &lt;open, open&gt; -- &lt;554, 560&gt;<p>There&#x27;s not much difference to any of these four. As long as you pick a singular choice, get comfortable with its quirks, and make it consistent across your organization, you get benefits.<p>The main reason we do [closed, open&gt; is because Dijkstra (father of structured programming back in the 1960s), argued to use [closed, open&gt;, when presented with all these options. (and argued for zero-indexed as well).<p>The &quot;[closed, closed]&quot; set is one-too-small (559 - 555 == 4), so you need to add +1 to the representation.<p>The &lt;open, open&gt; set is one-too-large: (560 - 554) == 6. So this too seems prone to off by one error.<p>[closed, open&gt; and &lt;open, closed] are both the correct size of 5 when you subtract, but both &quot;includes&quot; a number that doesn&#x27;t exist. In [closed, open&gt;, the latter number isn&#x27;t part of the array (560 is &quot;one past the end), while in &lt;open, closed&gt;, the first number isn&#x27;t part of the array.<p>Make that what you will of it. [closed, open&gt; became a programmer convention because of these reasons. The important bit is to know all the quirks &#x2F; off by one errors associated with this representation.
评论 #33706624 未加载
评论 #33707059 未加载
评论 #33707286 未加载
评论 #33707187 未加载
jmull超过 2 年前
Half-closed is generally good because it tends to reduce off-by-one errors.<p>But this article overstates the case. Especially for floating-point, where the distinction between a &lt; b and a &lt;= b is not straightforward. Some times you’re modeling closed intervals, and in that case using closed intervals is the right decision.<p>The “splitting by time” section should probably just be removed, since it confuses the point and doesn’t add anything. The scenario doesn’t really make sense (if you wanted this you’d store the registration time and get the hour you’d be better off by truncating the value, not using an interval). Also, if you’re going to be doing math on time values, you better know the precision of the values you’re working with (among many other things). Intervals, however closed or open aren’t going to help you there.<p>Maybe I shouldn’t criticize so much, since I agree with the general point. But this makes the case awkwardly.
评论 #33706357 未加载
评论 #33708283 未加载
eigenspace超过 2 年前
There are convincing cases one can make in favour of half-open intervals (at least in certain circumstances), but this isn’t it.<p>This is just a rambling, absolutist mess.
评论 #33704274 未加载
评论 #33703431 未加载
igammarays超过 2 年前
Why would you want a half-open interval when booking an AirBnB or flight? If I search for flights from February 24 to February 24 I don’t expect the empty interval.
评论 #33705322 未加载
评论 #33705154 未加载
评论 #33706758 未加载
评论 #33705637 未加载
评论 #33706030 未加载
评论 #33706124 未加载
chenglou超过 2 年前
Quite a few APIs use a pair of `{start, length}` instead, which in the context of the post&#x27;s example, is even clearer. Empty interval would be `length == 0`, time interval would be a single array of `starts`, etc. Fewer subtractions (to get length) usually end up nicer too.
BiteCode_dev超过 2 年前
It&#x27;s the default in Python, and it&#x27;s more helpful that not, so I would say it&#x27;s a good design decision. But &quot;always&quot; is a dangerous word in engineering, and in this case, definitly not warranted.<p>Case in point, last week I worked with list ofdates, and I needed the last date to bracket my sliding windows as a time period cleanly.
knorl超过 2 年前
I think this advice could be better summed up into: to minimise off-by-one errors, choose a consistent strategy for describing intervals, and stick with it as much as is sensible.
评论 #33703882 未加载
branko_d超过 2 年前
Just for completeness I&#x27;ll mention that there is another style:<p><pre><code> start, count </code></pre> This seems to be popular in .NET ecosystem.
评论 #33708752 未加载
评论 #33708107 未加载
vglocus超过 2 年前
I have recently been on the other side of this argument for specific case.<p>In our case we (users of our API) are to specify date ranges, representing a list of partitions. So we are not counting nights between dates, but rather a set of daily or hourly buckets.<p>Here (maybe even only here) I argue that inclusive ranges feel more intuitive.<p>I find it much more intuitive to represent the 1st 7 days of January as<p>[&#x27;2022-01-01&#x27;, &#x27;2022-01-07&#x27;]<p>compared to<p>[&#x27;2022-01-01&#x27;, &#x27;2022-01-08&#x27;).<p>Another very common example is to specify the last 7 days (incl &#x27;today&#x27;) in which case I find<p>[today().minusDays(6), today()]<p>to be a clearer representation than<p>[&#x27;today().minusDays(6)&#x27;, &#x27;today().plusDays(1)&#x27;)
评论 #33706368 未加载
andreareina超过 2 年前
*half-open intervals. There have been times I needed an (open, closed] interval. But there have also been times when I wanted a fully closed interval because I was setting an arbitrary limit and it&#x27;s easier to tell a user &quot;100 is the maximum&quot; versus &quot;it must be below 100”, so what value should be put to max out out, 99? 99.99? etc<p>To add some nuance I&#x27;d say that if you&#x27;re dividing a larger interval into smaller subintervals then a half-open one is probably what you want.
zasdffaa超过 2 年前
I know Dijkstra&#x27;s paper and it&#x27;s short, good and should be read but this article is wrong in saying <i>always</i>. It feels like a newbie programmer came across a good thing then lost all proportion; use the right tool for the right job, as ever.
评论 #33717986 未加载
评论 #33706345 未加载
the_cramer超过 2 年前
This depends on use case. If you are doing a frontend layer on top of closed-open, then the frontend will have to handle the points the article is rambling about.<p>Users are used to selecting a daterange in closed closed format for example.
评论 #33703623 未加载
ur-whale超过 2 年前
Wholeheartedly agree that sticking - where possible - to [closed, open) is a good idea. It has helped me tremendously when implementing, e.g. computational geometry algorithm. Robust triangle rasterization comes to mind.<p>Another interesting point: in the weird corner of the world where I grew up, half-open intervals were always denoted : [low_bound, hi_bound[<p>I am of course completely biased, but I&#x27;ve always found this notation much more elegant and intuitively obvious than the [low_bound, hi_bound) that seems to be the prevalent norm in the anglo world.<p>Using &#x27;[&#x27; after the upper bound clearly shows that we&#x27;re open at the top whereas the &#x27;)&#x27; is fairly arbitrary.<p>And while I&#x27;m on the topic of weird culture-induced quasi-arbitrary biases: I had a math teacher that would bark (and I mean BARK!) at us if we ever used &#x27;&gt;&#x27; in inequalities.<p>The justification was that with this constraint, all inequalities ended up written and laid out with its two members respecting the standard &quot;left-to-right&quot; drawing of the real line, which made it much easier to picture what was going on geometrically.<p>It also enforced consistency throughout a long demonstration - one less thing added to the cognitive load.<p>He was made fun of a lot by the student body, of course, but later in life, as a programmer, I have found myself sticking to the habit and I always force myself to mostly use &#x27;&lt;&#x27;, very rarely &#x27;&lt;=, and almost never &#x27;&gt;&#x27; and &quot;&gt;&quot;.<p>I find this makes code much more readable, just like back in the days of my old teacher with math inequalities., and pretty much for the exact same reasons.<p>Of course, doing that does not help at all when reading other folks code, those uncivilized heretical users of the &#x27;greater than&#x27; form.
chkas超过 2 年前
Python uses &quot;closed open&quot; intervals with `range(0, n)`, the reverse is then `range(n - 1, -1, -1)`, which is then highly unintuitive. This in connection with 0-based array indexing makes certain algorithms then very cumbersome. For example <i>Knuth-Shuffle</i>. In Python this is:<p><pre><code> from random import randrange x = [10, 20, 30, 40, 50 ] for i in range(len(x) - 1, 0, -1): r = randrange(i + 1) x[i], x[r] = x[r], x[i] print(x) </code></pre> With 1-based indexing and inclusive ranges it would be much more understandable:<p><pre><code> a[] = [ 10 20 30 40 50 ] for i = len a[] downto 2 r = random i swap a[i] a[r] end print a[]</code></pre>
评论 #33705556 未加载
评论 #33706107 未加载
评论 #33711211 未加载
评论 #33705614 未加载
评论 #33705572 未加载
sshine超过 2 年前
This is one of those &quot;well, of course!&quot; pieces.<p>But I&#x27;ve bookmarked it, in case I run into someone who thinks they disagree, in which case I can offload the explanation.<p>I had a similar incident with colleagues who had discovered the &quot;Default&quot; trait and starting adding defaults to everything, including things that didn&#x27;t have good defaults, and things where they didn&#x27;t mean default but actually something quite specific such as &quot;empty&quot;. The canonical &quot;don&#x27;t do that!&quot; blog post didn&#x27;t exist, so I had to create one.
评论 #33704109 未加载
enqk超过 2 年前
I think this has to do with the nature of the metric underneath. Closed-open intervals are the way to go for integers. However they don’t seen to be a good fit for sampling from continuuous space
评论 #33704769 未加载
personalityson超过 2 年前
Closed&#x2F;open makes sense for continuous measures, for integers closed&#x2F;closed is more readable
评论 #33706517 未加载
评论 #33708316 未加载
bheadmaster超过 2 年前
I prefer [a, b) intervals because they encode two pieces of important information directly:<p>1. The first element (a)<p>2. The length (b-a)<p>Which are what we most often need.
评论 #33704415 未加载
zx8080超过 2 年前
Am I the only one who noticed a bit unusual (or not?) ligature for &#x27;st&#x27;?
评论 #33705606 未加载
评论 #33704586 未加载
评论 #33704439 未加载
Gehinnn超过 2 年前
Don&#x27;t call you integer bound vars `start` and `end` please. Either use `start` and `endExclusive` or start and length - this greatly reduces confusion.<p>In my experience, half opened integer intervals lead to fewer `- 1` in the code.
评论 #33709363 未加载
评论 #33722083 未加载
评论 #33708352 未加载
评论 #33708365 未加载
jwilk超过 2 年前
&gt; You could try [T, T-1], but that&#x27;s a bit clunky and it won&#x27;t work if T is a decimal number.<p>Huh? What do they mean by &quot;decimal number&quot;?
评论 #33714142 未加载
评论 #33709816 未加载
hans_castorp超过 2 年前
FWIW, Postgres converts all ranges (=interval in this context) for discrete data types to half open intervals even when a closed one was requested.<p>So the daterange &#x27;[2022-01-01, 2022-01-07]&#x27; will result in [2022-01-01,2022-01-08) and the integer range &#x27;[1,7]&#x27; will result in &#x27;[1,8)&#x27;<p>So it seems the Postgres devs agree with the author.<p>Edit: typo fixed for integer range
评论 #33706807 未加载
return_to_monke超过 2 年前
I am surprised I can&#x27;t see this here. Wasn&#x27;t anyone else taught [closed; closed] and ]open; open[ notation in school?
评论 #33708171 未加载
评论 #33707072 未加载
评论 #33707541 未加载
评论 #33707165 未加载
nvartolomei超过 2 年前
E. W. Dijkstra constructed a similar argument to argue that numbering should start at 0 <a href="https:&#x2F;&#x2F;www.cs.utexas.edu&#x2F;users&#x2F;EWD&#x2F;transcriptions&#x2F;EWD08xx&#x2F;EWD831.html" rel="nofollow">https:&#x2F;&#x2F;www.cs.utexas.edu&#x2F;users&#x2F;EWD&#x2F;transcriptions&#x2F;EWD08xx&#x2F;E...</a>
green-in-gold超过 2 年前
The other nice property of [closed, open) intervals is that they concatenate perfectly: [a, b) ++ [b, c) == [a, c)
评论 #33710225 未加载
评论 #33708514 未加载
alexchantavy超过 2 年前
Dumb question but why is ‘[‘ called ‘closed’ and ‘)’ called ‘open’? I somehow would have thought the reverse.
评论 #33714242 未加载
评论 #33725258 未加载
nequo超过 2 年前
As it goes with maxims like this, it depends on the problem domain. In probability theory and statistics, a cumulative distribution function is defined as F(x) := Pr(X &lt;= x), not Pr(X &lt; x).<p>Like others are saying, it is consistency within the code base that probably matters the most.
评论 #33708273 未加载
runarberg超过 2 年前
The notation here really bothered me. The author defines the [closed, open) interval [a, b) as the list of all numbers number x that fulfill a ≤ x &lt; b. Good so far, but when they talk about the empty interval [a, a) we get into problem because a ≤ x &lt; a is a nonsensical statement. a cannot be equal to and strictly less then it self.<p>I think this is a problem when borrowing math concepts to programming. What the author is really talking about here is slicing, not intervals, and the slicing behavior is hopefully well defined on the construct you are working with, most of the time in a manner that makes sense to each construct, or in a consistent manner to other related constructs in the language.<p>If the author would stick with programming concepts, I don’t think this is a rule we should abide to, rather, a guideline which can be employed. And I think most programmers value consistency, so this really isn’t that much of an issue.
评论 #33708761 未加载
评论 #33709771 未加载
评论 #33717568 未加载
bob1029超过 2 年前
I was just watching YouTube series on arithmetic coding and I was wondering why the intervals were specified this way. Makes a lot more sense now. The &quot;b - a&quot; use case is quite prevalent there.
danans超过 2 年前
What&#x27;s with the funny connected &quot;st&quot; in the article? I&#x27;ve never seen that before.
评论 #33708342 未加载
phoe-krk超过 2 年前
How does [2, 2) make sense?
评论 #33714387 未加载
eurasiantiger超过 2 年前
This is not universal advice. If it’s nonsensical for your app to have start-end events of zero length, nothing in the article applies, and using closed intervals does make things a bit cleaner.