列表与元组——使用什么以及何时使用?
Lists vs. Tuples - What to use and when?
我试图掌握 Lists 和 Tuples 在 Elixir
中的区别。从 Elixir 指南的 Basic Types 部分,我了解到:
- 列表存储为链接项
- 更新列表很快(仅在前置时)
- 获取列表项很慢
- 获取列表信息(size/length)很慢
- 元组元素存储在一起
- 获取元组信息速度快
- 获取元组元素很快
- 修改元组很昂贵
好的,没关系,但是我仍然不确定时该用什么。我看到大多数方法 return 一个元组,但其他地方都使用列表,并且许多方法接受列表作为输入,而不是元组。根据上述几点,元组不应该用于传递数据,因为从用户给定值的元组中读取会很快吗?
我还注意到元组不可枚举,这是怎么回事?在它们上面使用 Enum
不会比在列表上使用它更快吗?
如果有人可以帮助我更好地理解它们,可能是通过举例说明何时使用什么,那就太棒了。
我不是专家,但这是我的理解:
在幕后,列表是一个链表。因此它具有链表的性能特征。也就是说,得到长度是 O(n) 因为我必须遍历整个列表。同样,列表也具有链表的优点;也就是说,很容易通过添加到前面来增长它。
我不确定引擎盖下的元组是什么,但我知道它不是链表。 2013 年有人在 Elixir 语言邮件列表中询问枚举元组,这是回复的一部分:
"Tuples also aren't meant to be iterated over, don't get confused by
the fact that you could using elem/2 and size/1. Tuples are for
storing multiple pieces of information together, which does not imply
that they are intended for storing a collection."
-- Peter Minten
"Another explanation would be that tuples are poor man's records. In
other words, a tuple represents a single piece of data, a single
value, albeit aggregate. You cannot take away an element from a tuple
without changing the semantic meaning of that particular tuple value.
"This is contrary to lists and other collections that store many
values independent values. Taking a value away from list simply
reduces the length of the list. It doesn't affect semantic meaning of
anything."
-- 阿列克谢·肖利克
换句话说,不能仅仅因为元组和列表之间存在表面上的相似性就认为行为是相同的。
您已经很好地总结了这些差异,因此在任何情况下,其中一项很重要,它应该可以帮助您决定使用哪一项。
考虑的方式是列表是开放式数据结构,它们的大小可以在运行时变化,而元组在编译时具有固定大小设置。
例如,如果您想存储用户在 iex
会话期间发出的所有命令,您需要一个列表 - 该列表的长度将取决于该会话中给出的命令数量。将此与元组的典型用例进行对比 - 从方法返回 {:ok, result}
或 {:error, reason}
- 这里元素的数量是预先知道的,因此您不会为性能付出不可接受的代价元组的改进。
至于枚举 - 元组在概念上不是集合,每个元素的位置也应该表示它的角色。考虑一个 {:ok, #PID<0.336.0>}
元组——迭代它首先会得到一个 :ok
然后是一个 #PID<0.336.0>
,编写一个以统一方式作用于这些东西的函数会很奇怪。
除了已经说过的内容之外,帮助我将元组与列表区分开来的是类似于数据库中的行。如果你这样想一个元组,就很容易看出元组中的信息是如何相互关联的,而且你为什么不把它用作 Enumerable 的原因也很明显。
由于有人提到他们不确定元组在幕后是什么样子,所以元组类似于数组,因为数组和元组都将元素存储在连续的内存中。因此,当您在链表上使用数组时,就像在 Elixir 中在列表上使用元组一样,遵循相同的规则。
如果您熟悉 Java:
- 列表就像
LinkedList
。
- 元组类似于
ArrayList
。
元组旨在保存固定数量的元素,这就是它们预先分配内存的原因。基本上元组并不意味着改变(虽然它是可能的但很昂贵)。他们提供了一条相关信息。
例如:地理坐标{43.258389, -2.924405}
相反,列表更适合动态集合(它们的修改成本更低)。
我发现这个 post 非常有用:https://blog.appsignal.com/2018/08/21/elixir-alchemy-list-vs-tuples.html
我试图掌握 Lists 和 Tuples 在 Elixir
中的区别。从 Elixir 指南的 Basic Types 部分,我了解到:
- 列表存储为链接项
- 更新列表很快(仅在前置时)
- 获取列表项很慢
- 获取列表信息(size/length)很慢
- 元组元素存储在一起
- 获取元组信息速度快
- 获取元组元素很快
- 修改元组很昂贵
好的,没关系,但是我仍然不确定时该用什么。我看到大多数方法 return 一个元组,但其他地方都使用列表,并且许多方法接受列表作为输入,而不是元组。根据上述几点,元组不应该用于传递数据,因为从用户给定值的元组中读取会很快吗?
我还注意到元组不可枚举,这是怎么回事?在它们上面使用 Enum
不会比在列表上使用它更快吗?
如果有人可以帮助我更好地理解它们,可能是通过举例说明何时使用什么,那就太棒了。
我不是专家,但这是我的理解:
在幕后,列表是一个链表。因此它具有链表的性能特征。也就是说,得到长度是 O(n) 因为我必须遍历整个列表。同样,列表也具有链表的优点;也就是说,很容易通过添加到前面来增长它。
我不确定引擎盖下的元组是什么,但我知道它不是链表。 2013 年有人在 Elixir 语言邮件列表中询问枚举元组,这是回复的一部分:
"Tuples also aren't meant to be iterated over, don't get confused by the fact that you could using elem/2 and size/1. Tuples are for storing multiple pieces of information together, which does not imply that they are intended for storing a collection."
-- Peter Minten
"Another explanation would be that tuples are poor man's records. In other words, a tuple represents a single piece of data, a single value, albeit aggregate. You cannot take away an element from a tuple without changing the semantic meaning of that particular tuple value.
"This is contrary to lists and other collections that store many values independent values. Taking a value away from list simply reduces the length of the list. It doesn't affect semantic meaning of anything."
-- 阿列克谢·肖利克
换句话说,不能仅仅因为元组和列表之间存在表面上的相似性就认为行为是相同的。
您已经很好地总结了这些差异,因此在任何情况下,其中一项很重要,它应该可以帮助您决定使用哪一项。
考虑的方式是列表是开放式数据结构,它们的大小可以在运行时变化,而元组在编译时具有固定大小设置。
例如,如果您想存储用户在 iex
会话期间发出的所有命令,您需要一个列表 - 该列表的长度将取决于该会话中给出的命令数量。将此与元组的典型用例进行对比 - 从方法返回 {:ok, result}
或 {:error, reason}
- 这里元素的数量是预先知道的,因此您不会为性能付出不可接受的代价元组的改进。
至于枚举 - 元组在概念上不是集合,每个元素的位置也应该表示它的角色。考虑一个 {:ok, #PID<0.336.0>}
元组——迭代它首先会得到一个 :ok
然后是一个 #PID<0.336.0>
,编写一个以统一方式作用于这些东西的函数会很奇怪。
除了已经说过的内容之外,帮助我将元组与列表区分开来的是类似于数据库中的行。如果你这样想一个元组,就很容易看出元组中的信息是如何相互关联的,而且你为什么不把它用作 Enumerable 的原因也很明显。
由于有人提到他们不确定元组在幕后是什么样子,所以元组类似于数组,因为数组和元组都将元素存储在连续的内存中。因此,当您在链表上使用数组时,就像在 Elixir 中在列表上使用元组一样,遵循相同的规则。
如果您熟悉 Java:
- 列表就像
LinkedList
。 - 元组类似于
ArrayList
。
元组旨在保存固定数量的元素,这就是它们预先分配内存的原因。基本上元组并不意味着改变(虽然它是可能的但很昂贵)。他们提供了一条相关信息。
例如:地理坐标{43.258389, -2.924405}
相反,列表更适合动态集合(它们的修改成本更低)。
我发现这个 post 非常有用:https://blog.appsignal.com/2018/08/21/elixir-alchemy-list-vs-tuples.html