2015-05-27 2 views
2

Рассмотрим следующий пример:Замена значений в списке в диапазоне вокруг элемента

Это процедура, которая принимает список, порог и ширину и производит массив с элементами из списка, где значение находится ниже порог. Если значение в списке по индексу i превышает пороговое значение, элементы в результирующем массиве в ширину w около i затушеваны -1.

let a = [1;4;1;4;3;3;2] 
let w = 1 
let thresh = 3 

let res = Array.copy (a |> List.toArray) 
let mutable i = 0 
let N = a.Length 

while i < N do 
    if a.[i] > thresh then 
     let lower = if i-w < 0 then 0 else i-w 
     let upper = if i+w > N-1 then N-1 else i+w 
     for j in lower..upper do 
      res.[j] <- -1 
    i <- i + 1 

Выход для этого примера должен быть

[|-1; -1; -1; -1; -1; 3; 2|] 

Хотя это работает, мне было интересно, если такого рода ширины индекса манипуляции со списками/seqs/массивов можно сделать более функциональным способом с F #?

+0

ну, а 'Array.copy' и' mutable i' не нужны - остальное будет нетривиально для переписывания функциональным способом. – Carsten

+0

Это можно сделать рекурсивно, используя сопоставление образцов относительно легко, как один из способов сделать это. –

+0

Я думаю, что это не сложно для 'w = 1', но если вы хотите, чтобы' w' был самим аргументом, шаблон не был исправлен, поэтому это очень сложно сделать, но может быть, я просто глуп прямо сейчас - может вы даете быструю реализацию Джона? – Carsten

ответ

4

Ключом к переводу этого на более функциональный метод является мысль с точки зрения преобразования данных. Вы хотите вернуть значение на основе значений в определенном диапазоне, поэтому первое, что нужно сделать, - это преобразовать ваши данные в набор этих диапазонов, а затем выполнить операцию.

Это решение выглядит немного смешно, потому что Windowed не работает на частичных окнах, поэтому вам нужно предварительно и после добавления порогового значения (или ниже).

let replaceValues lst threshold width = 
    seq { 
     for n in 1 .. width -> threshold 
     yield! lst 
     for n in 1 .. width -> threshold 
    } 
    |> Seq.windowed (width * 2 + 1) 
    |> Seq.map (fun x-> 
      if x |> Seq.exists (fun x->x > threshold) then -1 
      else x |> Seq.skip width |> Seq.head) 
+0

Спасибо за объяснение. – kasperhj

Смежные вопросы