我有一个单词列表和一个相关的词性标签列表。我想使用每个索引元组作为.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
答案 0 :(得分:13)
你的代码对我来说非常好 - 大多数代码都处理一些加载和初始化,所以你可以做很多事情来简化那部分。作为Array.map2
的替代,您可以将Seq.zip
与Seq.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}}的较短版本中)的人来说,序列表达式可能更具可读性