Ocaml 如何填充现有列表/数组
我对reason/ocaml/functional编程是新手 我知道Ocaml 如何填充现有列表/数组,ocaml,reason,Ocaml,Reason,我对reason/ocaml/functional编程是新手 我知道List.append和[]@[]但这些函数将创建新列表,但如何填充现有列表/数组 填充列表的最佳方式是什么 填充阵列的最佳方法是什么?表示如果coords类型为let coords:array point=[] 或者对于这种情况,这是错误的流程(算法) 原因代码: type point = {x: int, y: int}; let coords: list point = []; let append raw =>
List.append
和[]@[]
但这些函数将创建新列表,但如何填充现有列表/数组
let coords:array point=[]代码>
type point = {x: int, y: int};
let coords: list point = [];
let append raw =>
Array.iter
(
fun data => {
let p = {x: data.x, y: data.y};
/* how to append p to coords */
()
}
)
raw;
JS模拟:
const coords = [];
const append = raw => raw.forEach({x, y} => {
coords.push({
x: process(x),
y: process(y)
});
});
欢迎来到理性
在Reason/OCaml中,列表是不可变的。在引擎盖下,它们是简单的单链表。每次“修改”它们时都会创建新的。下面是一个例子:
let a = [1, 2, 3];
let b = [0, ...a];
这类似于JavaScript的数组“spread”,除了这里使用现有的a
,在前面链接一个新节点0
,并将其命名为b<代码>a仍然指向[1,2,3]
(因此是“不可变的”)<代码>b现在是[0,1,2,3]
。这是有效的,因为[1,2,3]
部分是共享的
这样做的好处是,您不必担心将列表传递给其他人,并且不小心让一个模糊的函数修改它。List的不变性允许您纯粹通过查看您当前所关注的值来推断代码(因为它永远不会改变!)
列表的缺点是在末尾添加内容效率低下:
let c = a @ [4]
该操作基本上是获取一个项目的列表,[4]
,然后依次将[1,2,3]
的每个项目附加到该列表中。在性能方面是线性的。但从列表实现的简单性来看,历史上认为这是值得权衡的
所以3。如果您试图设置列表项,那么这是错误的流程
let newList=list.map(fun blablabla=>…)raw
Array.of\u list
和Array.to\u list
如果你被卡住了array.make newSize
分配一个新数组,然后通过array.set
填充它。如果要大量调整数组的大小,那么这是没有意义的,因此请选择正确的数据结构
对于JS编译,BuckleScript将ocaml数组编译为JS数组。因此,它是可变的和可调整大小的。您可以在下面找到熟悉的JS数组操作
作为一种通用的启发式方法,如果您想更改长度:请尝试filter
。如果要更改长度和包含的项目,请尝试向左折叠
。否则,map
最近,我们开始实现一些不可变、可调整大小、可选可变的数组。请继续收看 欢迎来到理性
在Reason/OCaml中,列表是不可变的。在引擎盖下,它们是简单的单链表。每次“修改”它们时都会创建新的。下面是一个例子:
let a = [1, 2, 3];
let b = [0, ...a];
这类似于JavaScript的数组“spread”,除了这里使用现有的a
,在前面链接一个新节点0
,并将其命名为b<代码>a仍然指向[1,2,3]
(因此是“不可变的”)<代码>b现在是[0,1,2,3]
。这是有效的,因为[1,2,3]
部分是共享的
这样做的好处是,您不必担心将列表传递给其他人,并且不小心让一个模糊的函数修改它。List的不变性允许您纯粹通过查看您当前所关注的值来推断代码(因为它永远不会改变!)
列表的缺点是在末尾添加内容效率低下:
let c = a @ [4]
该操作基本上是获取一个项目的列表,[4]
,然后依次将[1,2,3]
的每个项目附加到该列表中。在性能方面是线性的。但从列表实现的简单性来看,历史上认为这是值得权衡的
所以3。如果您试图设置列表项,那么这是错误的流程
let newList=list.map(fun blablabla=>…)raw
Array.of\u list
和Array.to\u list
如果你被卡住了array.make newSize
分配一个新数组,然后通过array.set
填充它。如果要大量调整数组的大小,那么这是没有意义的,因此请选择正确的数据结构
对于JS编译,BuckleScript将ocaml数组编译为JS数组。因此,它是可变的和可调整大小的。您可以在下面找到熟悉的JS数组操作
作为一种通用的启发式方法,如果您想更改长度:请尝试filter
。如果要更改长度和包含的项目,请尝试向左折叠
。否则,map
最近,我们开始实现一些不可变、可调整大小、可选可变的数组。请继续收看 这里有几种不同的方法。如果您想坚持使用注释中提到的
Js.Array
,可以这样做:
使用及
如果你想用Array.fold_left
和Array.append
来做,你可以按照@chenglou的建议用
rawArray|>Array.fold_left((a, b) =>
Array.append(a, [|{x: b[0], y: b[1]}|]), [||]);
它可能更干净,有一些辅助功能,如:
let concatMap = f =>
Array.fold_left((a, b) => Array.append(a, f(b)), [||]);
let newPoint = coord => [|{x: coord[0], y: coord[1]}|];
然后打电话:
let rawTuples = [|(3, 5), (4, 9), (9, 4)|];
let arrayTuples = rawTuples |> concatMap(a => [|{x: fst(a), y: snd(a)}|]);
使用助手也有助于我理解函数的每个部分在做什么
也可以使用元组
,因为它们只是ReasonML/Ocaml/Rescript中的数组
let rawTuples = [|(3, 5), (4, 9), (9, 4)|];
let arrayTuples = rawTuples |> concatMap(a => [|{x: fst(a), y: snd(a)}|]);
使用
您可以选择使用可变记录创建数组
这就是更新可变记录数组的方法。
let rawTuples = [|(3, 5), (4, 9), (9, 4)|];
let arrayTuples = rawTuples |> concatMap(a => [|{x: fst(a), y: snd(a)}|]);
let printCoords = coords => Array.iter(Js.log, coords);
type mutablePoint('a, 'b) = {
mutable x: 'a,
mutable y: 'b,
};
let data1: mutablePoint(int, int) = {x: 2, y: 4};
let data2: mutablePoint(int, int) = {x: 3, y: 4};
let data3: mutablePoint(int, int) = {x: 4, y: 4};
let isEven = n => {
n mod 2 == 0;
};
let multiplyByY = data => data.x = data.x * data.y;
let makeItOdd = data => data.x = data.x + 1;
let updateData = data => data.x->isEven
? data->makeItOdd : multiplyByY(data);
let points: array(mutablePoint('x, 'y)) = [|data1, data2, data3|];
let append = (fn, data) => {
Array.iter(x => {fn(x)}, data);
data;
};
points |> append(updateData);
Js.log("points after");
printCoords(points);
// points after { x: 3, y: 4 } { x: 12, y: 4 }{ x: 5, y: 4 }
let points2: array(mutablePoint('x, 'y)) = [|data1, data2, data3|];
let printCoords = coords => Array.iter(Js.log, coords);
printCoords(points2);
let rawData = [|[|1, 2|], [|3, 4|], [|9, 4|]|];
let update_x_on_point_i = (i, x) => points2[i].x = x;
let append = raw =>
Array.iteri(
(i, d) => {
let x: int = d[0];
update_x_on_point_i(i, x);
},
raw,
);
append(rawData);
Js.log2("points2 after: ", points2);
printCoords(points2);
// points2 after: [ { x: 1, y: 4 }, { x: 3, y: 4 }, { x: 9, y: 4 } ]
type point = {
x: int,
y: int,
};
let coords = [|{x: 9, y: 7}, {x: 2, y: 4}, {x: 3, y: 8}|];
Js.log("coords before");
Js.log("-------");
let append = raw =>
raw->Belt.Array.mapWithIndex(
_,
(i, r) => {
let new_point_i = {x: r[0], y: r[1]};
coords[i] = new_point_i;
},
);
let rawData = [|[|1, 2|], [|3, 4|], [|9, 4|]|];
append(rawData);
Js.log("coords after");
Js.log(coords);
coords before
[ { x: 9, y: 7 }, { x: 2, y: 4 }, { x: 3, y: 8 } ]
-------
coords after
[ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 9, y: 4 } ]
type data_item = {
symbol: string,
next: bool,
};
/* Convenience function for making data items. */
let make_data_item = (symbol, next) => {symbol, next};
let process = (data: list(data_item)) => {
/*
We track the current symbol as well as the result list in the folding function.
*/
let fold_func = ((current, result), {symbol, next}) =>
if (next) {
(symbol, [current, ...result]);
} else {
(current ++ symbol, result);
};
let (current, result) = List.fold_left(fold_func, ("", []), data);
/*
We need to reverse the result list because `[el, ...els]` above actually
builds it up in the _opposite_ order to the original input list.
*/
(current, List.rev(result));
};
let result =
process([
make_data_item("a", false),
make_data_item("b", false),
make_data_item("c", true),
make_data_item("d", false),
]);
/* result = ("cd", ["ab"]) */