我正在尝试编写一个有效的算法,它将有效地让我合并数据集(如sql join)。我想我需要使用Array.tryFindIndex,但语法让我迷失了。
根据下面的数据,我调用arrX我的“主机”数组,并希望返回一个有长度的int数组,并告诉我arrY中每个元素的位置(如果不是则返回-1)在那里)。 (一旦我知道这些索引,我就可以在长度为arrY.length的数据数组上使用它们)
let arrX= [|"A";"B";"C";"D";"E";"F"|]
let arrY = [|"E";"A";"C"|];
let desiredIndices = [|1; -1; 2; -1; 0; -1|]
看起来我需要以某种方式使用选项类型,我认为mapi2也在那里。 有谁知道怎么做到这一点? (我认为对于合并来自不同来源的数据集的人来说,这可能是一个非常有用的代码片段)
谢谢!
//This code does not compile, can't figure out what to do here
let d = Array.tryFindIndex (fun x y -> x = y) arrX
答案 0 :(得分:6)
tryFindIndex
函数搜索指定为第二个参数的数组中的单个元素。 lambda函数只获取一个参数,如果参数是您要查找的元素,则它应返回true
。 tryFindIndex
函数的类型签名显示:
('a -> bool) -> 'a [] -> int option
(在您的示例中,您将为其提供一个函数,该函数采用类型为'a -> 'a -> bool
的两个参数,这与预期的类型不兼容)。 tryFindIndex
函数返回一个选项类型,这意味着如果没有元素与谓词匹配,它会给你None
,否则它会给你Some(idx)
包含找到的元素的索引。
要获得所需的索引数组,您需要为输入数组的每个元素(tryFindIndex
)运行arrX
。这可以使用Array.map
函数完成。如果要在未找到元素的情况下获得-1,则可以使用模式匹配将None
转换为-1并将Some(idx)
转换为idx
:
let desired =
arrX |> Array.map (fun x ->
let res = Array.tryFindIndex (fun y -> x = y) arrY
match res with
| None -> -1
| Some idx -> idx)
可以使用序列表达式(而不是map
)编写相同的东西,这可能更具可读性:
let desired =
[| for x in arrX do
let res = Array.tryFindIndex (fun y -> x = y) arrY
match res with
| None -> yield -1
| Some idx -> yield idx |]
无论如何,如果你需要实现类似连接的操作,你可以更简单地使用序列表达式。在下面的示例中,我还添加了一些值(除了字符串键),以便您可以更好地了解它的工作原理:
let arrX= [|"A",1; "B",2; "C",3; "D",4; "E",5; "F",6|]
let arrY = [|"E",10; "A",20; "C",30|]
[| for x, i in arrX do
for y, j in arrY do
if x = y then
yield x, i, j |]
// Result: [|("A", 1, 20); ("C", 3, 30); ("E", 5, 10)|]
序列表达式简单地遍历所有arrX
元素,并且对于每个元素,它遍历所有arrY
元素。然后它测试键是否相同,如果它们是,它产生一个单独的元素。这不是特别有效,但在大多数情况下,它应该工作正常。
答案 1 :(得分:3)
编写一个自定义函数,如果没有找到则返回-1,如果找到则返回索引。接下来,使用Array.map使用此函数映射新数组:
let arrX= [|"A";"B";"C";"D";"E";"F"|]
let arrY = [|"E";"A";"C"|];
let indexOrNegativeOne x =
match Array.tryFindIndex (fun y -> y = x) arrY with
| Some(y) -> y
| None -> -1
let desired = arrX |> Array.map indexOrNegativeOne
printfn "%A" desired