f # массив.фильтр на основе массива bool

#f#

#f#

Вопрос:

если у меня есть array A , и у меня есть другой массив bool isChosen с такой же длиной A , A как я могу создать новый массив из isChosen того true места, где он находится,,? что-то вроде A.[isChosen] ? Я не могу использовать Array.filter напрямую, поскольку isChosen это не функция A элементов и не существует Array.filteri подобного Array.mapi .

Комментарии:

1. Похоже, zip это может быть удобно.

Ответ №1:

zip должен помочь:

 let l = [|1;2;3|]
let f = [|true; false; true|]

let r = [| for (v, f) in Seq.zip l f do if f then yield v|]
// or
let r = (l, f) ||> Seq.zip |> Seq.filter snd |> Seq.map fst |> Seq.toArray 
  

Ответ №2:

Попробуйте использовать zip-оператор

 seq.zip A isChosen 
|> Seq.filter snd
|> Seq.map fst
|> Array.ofSeq
  

Это создаст последовательность кортежей, в которых одно значение берется из A , а другое — из isChosen . Это позволит связать значения вместе и очень легко отфильтровать их в Seq.filter выражении

Комментарии:

1. 1, но обратите внимание, что Seq.filter (fun (_, right) -> right) это можно было бы упростить до Seq.filter snd , а аналогично для Seq.map (fun (left, _) -> left) до Seq.map fst .

2. @ildjam спасибо за рекомендацию. Я часто забываю о помощниках по кортежам

Ответ №3:

Это не так элегантно или «функционально», как другие ответы, но время от времени мне нравится ненавязчивое напоминание о том, что вы можете использовать циклы и индексы массива в F#:

 let A = [|1;2;3|]
let isChosen = [|true; false; true|]
let r = [| for i in 0..A.Length-1 do 
                if isChosen.[i] then 
                    yield A.[i] |]
printfn "%A" r
  

🙂

Комментарии:

1. моя первая попытка заключалась в использовании -> вместо do.. yield . почему -> не работает? Спасибо

2. Вы можете заменить do yield на -> синтаксис ‘short form’, если вы выполняете простое однострочное сопоставление, но если у вас есть какая-либо логика (например, if ), тогда ‘short form’ не существует. (Мне не нравится синтаксис ‘short form’, он добавляет мало значения и создает путаницу.)

Ответ №4:

И вот еще два способа, просто для демонстрации (даже) большего количества функций библиотеки F #:

 let A = [|1;2;3|]
let isChosen = [|true;false;true|]

let B = Seq.map2 (fun x b -> if b then Some x else None) A isChosen
        |> Seq.choose id
        |> Seq.toArray

let C = Array.foldBack2 (fun x b acc -> if b then x::acc else acc) A isChosen []
        |> List.toArray
  

Мой личный фаворит для понятности (и, следовательно, удобства сопровождения): ответ деско

 let r = [| for (v, f) in Seq.zip l f do if f then yield v|]