枚举 vs 索引 vs 迭代

5

我已经阅读Eric Lippert的博客有一段时间了(非常好,您应该去看看),在他的某篇文章的评论中,他提到他没有意图对一系列数字进行索引,而只是枚举它们。

枚举和索引之间有什么区别?我已经搜索了所有地方,并且当迭代被纳入方程式时,我变得更加困惑了。有人能解释一下这三个概念,甚至举个例子吗?在您将其标记为重复之前,请注意,我已经看过一些关于“Iterator vs Enumerator”的问题,但我尚未看到一个合适的解释(因此是这个问题)。谢谢你的帮助。

3个回答

5
在对Eric的文章进行评论时,有人观察到排列的大小呈指数增长,很快就会超出32位可表示的数字范围。Eric回答说,他没有意图对排列进行索引,也就是说没有定义一种编号方案来获取排列的顺序号。因此,他说,溢出32位不是他关心的问题:他的方法允许以某种顺序“枚举”或简单地“生成”所有排列,而不是提供一种按照某种编号方案获取第N个排列的方法。
相比之下,在一个讨论如何在不经过所有前置排列的情况下产生第N个排列的问题中讨论的问题,则要求作者为排列进行编号,所以整数的大小对他们很重要。
这里是上述问题中讨论的对排列进行编号的示例:
1 ABC
2 ACB
3 BAC
4 BCA
5 CAB
6 CBA

这种索引方案可以回答两个问题:
  • 一个特定排列的编号是多少?例如,BCA 的编号是 4。
  • 排列编号是 X,例如,5 是什么排列?(它是 CAB
这个问题可能比枚举所有排列更难,因为你需要生成一个编号方案。

很棒的东西,感谢你的帮助。现在看起来很明显...但是迭代和枚举有什么区别呢? - Dimitar Dimitrov
1
@DimitarDimitrov 在这个上下文中,枚举和迭代非常密切相关:枚举意味着产生所有排列,而迭代意味着在循环中进行它们。要枚举一个序列,您需要知道如何做到这一点;要迭代它,您需要实际执行它。在C#的上下文中,可以通过提供具有延迟执行的IEnumerabl<T>来枚举序列。然后他可以选择迭代该序列,例如使用foreach循环,或者做其他事情-例如取前几个元素,并丢弃其余的枚举。 - Sergey Kalinichenko
因此,简要总结一下,枚举是“生成”排列序列的行为,而迭代是“遍历序列”的行为?此外,不同的执行基本上意味着“知道如何枚举并在请求时执行”,不一定是预先执行。 - Dimitar Dimitrov
@DimitarDimitrov 是的,那就够接近了。 "Producing" 并不一定意味着在内存中生成序列,因此您可以通过向调用者提供一对 HasNextGetNext 方法来 "produce" 一个序列。 - Sergey Kalinichenko

1
你只能索引那些实际存在的东西。你可以使用operator []索引一个array,或者索引一个list(至少在C#中是这样,更加正式的计算机科学人员会感到不适)。但是你无法索引IEnumerable<T>,因为枚举只意味着你可以按顺序浏览所有项。但你无法跳转到特定项。
string text = "hello";

这是枚举:
foreach( var c in text ) Console.WriteLine(c);

这使用索引:
for( int i = 0 ; i < text.Length ; i++ ) Console.WriteLine(text[i]);

这是真实的数据:

var arr = new int[15]; 

这并不是真实的,number 中没有数据,只是一个提供枚举数据的承诺。您需要将其 实例化 以获得真实数据:
var number = GetNumbers();

这将产生无数个“1”。这不是真实的数据,而是一种如何枚举后生成真实数据的方法。
public IEnumerable<int> GetNumbers()
{
    while(true) yield return 1;
}

这非常有帮助!我希望我能够接受两个答案……或者至少可以投多次赞同! - Dimitar Dimitrov

1
概念上,枚举器和迭代器对于序列知之甚少。它们通常可以:
- 获取下一个项 - 检查当前元素是否为最后一个元素
当集合被修改时,它们可能会表现出不同的行为。这些类型非常适用于处理大量数据、流、LINQ 和惰性加载,因为它们一次只获取一个元素。要从序列中获取第 i 个元素,必须遍历所有先前的元素,这是一个 O(N) 的操作。您可以将它们视为链表数据结构。
索引器只能使用固定长度的内存,即使底层存储可能会收缩和增长(例如 List 类型)。索引器知道数据的类型以及需要多少存储空间或对象的引用需要多少存储空间。这使得索引器可以在 O(1) 中获取序列中的任何项,但缺点是必须将所有数据存储在内存中。它只是将索引乘以元素大小,并将结果加到起始地址,因此可以获得所需对象的值或引用。您可以将索引器视为数组数据结构。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接