f# - 处理没有可变性的元组流?

标签 f# tuples immutability

所以我想要一个接收 Tuple 数组并返回相同类型但具有不同值的函数。

我想要做的是一个返回这种值的函数:

f( [1,10; 2,20; 3,40; 4,70] ) = [2,10; 3,20; 4,30]

所以如你所见,第一个数字基本不变(除了第一个项目没有被选中),但最后一个数字是当前数字与前一个数字的减法(20 - 10 = 10, 40 - 20 = 20, ...).

我试图在 F# 中提出一个不涉及可变性 的算法(对前一个值使用累加器意味着我需要一个可变变量),但我做不到弄清楚。这可能吗?

最佳答案

使用内置函数。在这种情况下,您可以使用 Seq.pairwise .该函数采用一系列输入并生成一系列包含先前值和当前值的对。一旦你有了对,你就可以使用 Seq.map将对转换为结果 - 在您的情况下,获取当前值的 ID 并从当前值中减去先前的值:

input 
|> Seq.pairwise 
|> Seq.map (fun ((pid, pval), (nid, nval)) -> nid, nval-pval)

请注意,结果是一个序列 (IEnumerable<T>) 而不是一个列表 - 仅仅是因为 Seq模块包含更多(有用的)功能。您可以使用 List.ofSeq 将其转换回列表.

使用显式递归。如果您的任务不符合某些内置函数所涵盖的常见模式之一,那么答案就是使用递归(通常, 替换功能样式中的突变)。

为了完整起见,递归版本看起来像这样(这并不完美,因为它不是尾递归,所以它可能会导致堆栈溢出,但它演示了这个想法):

let rec f list = 
  match list with
  | (pid, pval)::(((nid, nval)::_) as tail) ->
      (nid, nval-pval)::(f tail)
  | _ -> []

这需要一个列表并查看列表的前两个元素 (pid, pval)(nid, nval) .然后它根据(nid, nval-pval)中的两个元素计算出新值。然后递归处理列表的其余部分(tail),跳过第一个元素。如果列表只有一个或更少的元素(第二种情况),则不返回任何内容。

可以使用“累加器”技巧编写尾递归版本。而不是写 newValue::(recursiveCall ...)我们将新产生的值累积在一个列表中作为参数保存,然后反转它:

let rec f list acc = 
  match list with
  | (pid, pval)::(((nid, nval)::_) as tail) ->
      f tail ((nid, nval-pval)::acc)
  | _ -> List.rev acc

现在您只需要使用 f input [] 调用该函数即可初始化累加器。

关于f# - 处理没有可变性的元组流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22543930/

相关文章:

.net - 为什么F#无法打开静态类?

c# - 什么是 C# 的 "moSTLy complete"(im) 可变性方法?

javascript - 在 React 中将一个大数组包装在一个对象中以避免深度克隆是作弊吗?

language-agnostic - 向量、集合和元组之间的差异

Java:只检查不可变对象(immutable对象)的equals()中的hashCode

asynchronous - 结合 F# 异步函数

使用 FParsec 解析日期和时间

f# - F# 中的教会数字

Java 和 Scala Tuple2 访问错误

python - 在 python 列表理解中解包元组(不能使用 *-operator)