【问题标题】:Are upper bounds of indexed ranges always assumed to be exclusive?是否总是假定索引范围的上限是互斥的?
【发布时间】:2011-01-27 06:30:46
【问题描述】:

所以在 Java 中,只要给出索引范围,上限几乎总是排他性的。

来自java.lang.String

substring(int beginIndex, int endIndex)

返回一个新字符串,它是该字符串的子字符串。子字符串从指定的beginIndex 开始并延伸到索引endIndex - 1 处的字符

来自java.util.Arrays

copyOfRange(T[] original, int from, int to)

from - 要复制的范围的初始索引,包含
to - 要复制的范围的最终索引,不包含。

来自java.util.BitSet

set(int fromIndex, int toIndex)

fromIndex - 要设置的第一位的索引。
toIndex - 要设置的最后一位之后的索引。

如您所见,Java 确实试图使其成为一个一致的约定,即上限是排他的。

我的问题是:

  • 这是官方权威推荐吗?
  • 是否存在值得我们警惕的明显违规行为?
  • 这个系统有名字吗? (又是“基于 0”与“基于 1”)

澄清:我完全理解基于 0 的系统中的 N 对象集合被索引为 0..N-1。我的问题是,如果给定一个范围(2,4),它可以是 3 项或 2 项,具体取决于系统。你怎么称呼这些系统?

再次,问题不是“第一个索引0最后一个索引N-1”与“​​第一个索引1最后一个索引N”系统;这就是所谓的 0-based vs 1-based 系统。

问题是“(2,4) 中有 3 个元素”与“(2,4) 中有 2 个元素”系统。你怎么称呼这些,是官方认可的吗?

【问题讨论】:

  • 称为半开范围。
  • 啊,是的,我以前听过这个词。那么你会说 Java 集合是“基于 0 的半开范围”吗?

标签: java collections indexing range


【解决方案1】:

它只是基于 0 到 n-1

一个列表/数组包含 100-9 索引。

您不能有一个基于 0 索引的列表,即 0-n,其中 cout 为 n,其中包含不存在的项目...

这是典型的工作方式。

  1. 是的
  2. Excel 范围/工作表/工作簿。
  3. Index (information technology)

【讨论】:

  • 我了解基于 0 的系统中 N 对象的集合的索引为 0..N-1。我的问题是,如果给定一个范围 (2,4),那是 3 个项目还是 2 个项目?
  • 这将取决于您引用的对象列表的上下文。如前所述,文档应该帮助您解决这个问题。它很可能是基于 0 的,但正如我所提到的,存在偏差......
【解决方案2】:

一般来说,是的。如果您使用类似 C 语法的语言(C、C++、Java),那么数组是零索引的,并且大多数随机访问数据结构(向量、数组列表等)将是零索引的也是。

从零开始索引意味着数据结构的大小总是比数据结构中的最后一个有效索引大一。当然,人们经常想知道事物的大小,因此谈论大小比谈论最后一个有效索引更方便。 人们习惯于以排他的方式谈论结束索引,因为数组 a[] 的长度为 n 元素,其最后一个有效元素是 a[n-1]

使用排他索引作为结束索引还有另一个优点,即您可以通过从排他结束索引中减去包含开始索引来计算子列表的大小。如果我调用myList.sublist(3, 7),那么我会得到一个包含7 - 3 = 4 元素的子列表。如果sublist() 方法对列表的两端使用了包含索引,那么我需要添加一个额外的 1 来计算子列表的大小。

当起始索引是一个变量时,这特别方便:获取从 i 开始的 myList 的子列表,即 5 个元素的长度就是 myList.sublist(i, i + 5)

话虽如此,您应该始终阅读 API 文档,而不是假设给定的开始索引或结束索引将是包容性或排斥性的。同样,您应该记录自己的代码以指示任何边界是包含还是排除。

【讨论】:

  • +1 表示“您应该始终阅读 API 文档”和“您应该记录自己的代码以表明”
  • 只是为了澄清与 OP 的相关性,我认为 Java 中半开范围的流行直接来自于 C 中半开范围的使用,而这反过来又是从零开始的索引。因此,我认为关于从零开始的索引的讨论 与原始问题相关。 (话虽这么说,如果我没有在我的原始答案中明确说明从零开始的索引和半开范围之间的联系,那是我的错。)
【解决方案3】:

这种做法是由 Josh Bloch 作为合同引入 Collections API 的。

之后它成为 java 中的标准,当任何人决定创建公共库时,他认为他应该遵守合同,因为用户希望在新库中看到已知行为。

【讨论】:

  • 那么这就是“布洛赫系统”吗?在 Java/Java Collections Framework 之前,这肯定有历史使用方式吗?
  • 我不知道它的名字,也不确定它是否存在。我在 youtube 上观看了 Josh Bloch 谈论 API 设计中的良好原则的视频。他在那里说包容的下界和独占的上界原则实际上是一个标准,在开发公共图书馆时不应该违反。他还提到他是第一个(或者是第一个,我不记得了)在 java 中引入它的人。
  • 我很困惑为什么人们不赞成你,因为与这里的其他一些人不同,你实际上“明白”了我的要求。
  • 我不是反对者 ;-),但我很好奇这份合同的记录在哪里。这是一个在 Collections API 中一直遵循的模式,当然每个人都注意到了它,但我从未见过它被命名或集中记录。无论如何,传递数组或字符串大小的模式(如果起始索引为零,则与排他结束索引相同)可以追溯到 Java 之前很久,对吧?
  • @Joe Carnahan:我不确定它是否记录在任何地方(但如果我不知道并且您不知道,那么这并不意味着它没有记录)但是每个中级或高级Java开发人员知道,如果您希望其他人使用您的产品,则不应违反此原则。 Apache Commons 和 Google Collections 以及许多其他库(例如 Google Data API)遵守此合同。
【解决方案4】:

array like 数据结构中的索引确实总是从 0 开始。 String 基本上由 char[] 支持。 Collections 框架是基于数组等的。这使得设计/维护/使用 API 更容易,而无需更改访问数组中所需元素的“幕后”方式。

不过也有一些“例外”,例如PreparedStatement 的基于参数索引的setter 方法和ResultSet 的基于columnindex 的getter 方法。它们是基于 1 的。在幕后,它们也并不真正代表一组值。

这可能会带来一个新问题:“为什么数组索引从零开始?”。现在,我们受人尊敬的计算机编程科学家E.W. Dijkstra 解释了here 为什么它应该从零开始。

【讨论】:

    【解决方案5】:

    Credit 在他的评论中提到 FredOverflow 说这被称为“半开区间”。所以推测,Java 集合可以描述为“基于 0 的半开范围”。

    我在别处整理了一些关于半开与封闭范围的讨论:


    siliconbrain.com - 16 good reasons to use half-open ranges(为简洁而编辑):

    • [n, m) 范围内的元素数仅为m-n(而不是m-n+1)。
    • 空范围是[n, n)(而不是[n, n-1],如果n 是一个已经指向列表第一个元素的迭代器,或者n == 0,这可能是个问题)。
    • 对于浮点数,您可以编写 [13, 42)(而不是 [13, 41.999999999999])。
    • +1-1 在处理范围时几乎从不使用。如果它们很昂贵(因为它是日期),这是一个优势。
    • 如果您在某个范围内编写查找,则可以通过将结尾返回为找到的位置轻松指示没有找到任何东西的事实:if( find( [begin, end) ) == end) 没有找到。
    • 在数组下标以 0 开头的语言(如 C、C++、JAVA、NCL)中,上限等于大小。

    Half-open versus closed ranges

    半开范围的优点:

    • 空范围有效:[0 .. 0]
    • 易于子范围转到原始末尾:[x .. $]
    • 易于拆分范围:[0 .. x][x .. $]

    封闭范围的优点:

    • 对称。
    • 可以说更容易阅读。
    • ['a' ... 'z']'z' 之后不需要尴尬的+ 1
    • [0 ... uint.max] 是可能的。

    最后一点非常有趣。如果Integer.MAX_VALUE 可以合法地在一个范围内,那么写一个带有半开范围的numberIsInRange(int n, int min, int max) 谓词真的很尴尬。

    【讨论】:

      【解决方案6】:

      考虑半开范围的简单方法是:第一项标识范围内元素的开始,第二项标识范围之后元素的开始。记住这一点,这一切都更有意义。另外,根据@polygenelubricants 的回答,在许多情况下,算法的效果更好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 2014-03-10
        相关资源
        最近更新 更多