f # перебирает два массива, используя функцию из библиотеки c # - PullRequest
5 голосов
/ 18 мая 2010

У меня есть список слов и список связанных частей речевых тегов. Я хочу перебрать оба, одновременно (сопоставленный индекс), используя каждый индексированный кортеж в качестве входных данных для функции .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 Ответ

13 голосов
/ 18 мая 2010

Ваш код выглядит довольно хорошо для меня - большая часть его имеет дело с некоторой загрузкой и инициализацией, поэтому вы не могли бы многое сделать, чтобы упростить эту часть. В качестве альтернативы 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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...