f#使用c#库中的函数迭代两个数组

时间:2010-05-18 00:09:57

标签: f# arrays iteration

我有一个单词列表和一个相关的词性标签列表。我想使用每个索引元组作为.NET函数的输入同时迭代两个(匹配索引)。这是最好的方式(它有效,但对我来说不自然):

let taggingModel = SeqLabeler.loadModel(lthPath + 
                      "models\penn_00_18_split_dict.model");
let lemmatizer = new Lemmatizer(lthPath + "v_n_a.txt")
let input = "the rain in spain falls on the plain"

let words = Preprocessor.tokenizeSentence( input )
let tags = SeqLabeler.tagSentence( taggingModel, words )
let lemmas = Array.map2 (fun x y -> lemmatizer.lookup(x,y)) words tags

1 个答案:

答案 0 :(得分:13)

你的代码对我来说非常好 - 大多数代码都处理一些加载和初始化,所以你可以做很多事情来简化那部分。作为Array.map2的替代,您可以将Seq.zipSeq.map结合使用 - zip函数将两个序列合并为一个包含具有匹配索引的元素对的序列:

let lemmas = Seq.zip words tags 
          |> Seq.map (fun (x, y) -> lemmatizer.lookup (x, y)) 

由于lookup函数采用你得到的元组作为参数,你可以写:

// standard syntax using the pipelining operator
let lemmas = Seq.zip words tags |> Seq.map lemmatizer.lookup

// .. an alternative syntax doing exactly the same thing
let lemmas = (words, tags) ||> Seq.zip |> Seq.map lemmatizer.lookup

第二个版本中使用的||>运算符采用包含两个值的元组,并将它们作为两个参数传递给右侧的函数,这意味着(a, b) ||> f表示f a b|>运算符左侧只有一个值,因此(a, b) |> f表示f (a, b)(如果函数f预期元组而不是两个,空格分隔,则可以使用lemmas参数)。

如果最后需要Array.ofSeq作为数组,则需要将Seq添加到处理管道的末尾(所有IEnumerable<T>函数都可以使用序列,对应[| .. |]

另一种选择是使用序列表达式(如果你需要的话,你可以使用let lemmas = [| for wt in Seq.zip words tags do // wt is tuple (string * string) yield lemmatizer.lookup wt |] 直接构造一个数组):

Seq.map

是否使用序列表达式 - 这只是个人偏好。在这种情况下,第一个选项似乎更简洁,但对于不太熟悉部分函数应用程序(在使用{{1}}的较短版本中)的人来说,序列表达式可能更具可读性