2015-06-10 3 views
3

У меня есть проблема, которую я упростил для этого вопроса.
Давайте просто скажем, что у меня есть 2 списка. Первый фактически представляет список классов, но для этой цели, допустим, это просто представляет список ints (2,4,6,8,10). У меня есть другой список ints, который представляет флаги, указывая, хочу ли я включать/исключать соответствующие значения из первого набора.
(Это не лучший пример, но должно быть достаточно для помощи мне решить мою реальную проблему.)F # Я хочу отфильтровать свой вывод

let set1 = [2;4;6;8;10] 
let set2 = [1;0;0;1;1] 

Мой требуемый выход набор:

[2;8;10] 

Это мой код:

let solution = 
    List.map2 (fun a b -> 
     match b with 
     | 1 -> a 
     | _ -> 0 
    ) set1 set2 

Это производит следующие выходные данные:

val solution : int list = [2; 0; 0; 8; 10] 

Как отфильтровать эти нежелательные нули?
Вместо | _ -> 0 Я в идеале хочу вернуть нуль, а затем отфильтровать все нули.

Ваша помощь будет высоко оценена!

ответ

4

Это один, кажется разумным легко:

let filterWith set2 set1 = 
    List.zip set1 set2 
    |> List.filter (fun (_,x) -> x=1) 
    |> List.map fst 

использование:

let set1 = [2;4;6;8;10] 
let set2 = [1;0;0;1;1] 

set1 |> filterWith set1 

, если вы решили использовать список bool с для вашего set2 он мог получить немного приятнее:

let filterWith set2 set1 = 
    List.zip set1 set2 
    |> List.filter snd 
    |> List.map fst 

использование:

let set1 = [2;4;6;8;10] 
let set2 = [true;false;false;true;true] 

set1 |> filterWith set1 
+3

Последние два могут быть заменены с помощью 'List.choose (fun (x, key) -> if key then Some x else None)' – bytebuster

+0

... или даже 'List.choose (function (x, true)) -> Некоторые x | _ -> None) ' – bytebuster

3
List.zip set1 set2 
|> List.filter (snd >> (<>) 0) 
|> List.map fst 
2

Вот еще один вариант с использованием свёртки и функция предиката держать флаги родовым. Я имел некоторую забаву с флагами :)

let filterByFlag pred l flags = 
    List.zip l flags 
    |> List.fold (fun s (x,flag) -> if pred(flag) then x::s else s) [] 
    |> List.rev 

let l = [2;4;6;8;10] 
let flags = ["";"";"";"";""] 

filterByFlag (fun t -> t = "") l flags 
>val it : int list = [2; 8; 10] 
+0

Очень удобно. Спасибо за ваши входные и интересные флаги, которые вы туда отправили :-) – z0mbi3

+0

@Kevin, вместо сгиба + rev вы можете использовать foldBack :) –

2

Я добавлю 3 варианта: :)

let set1 = [2;4;6;8;10] 
let set2 = [1;0;0;1;1] 

let filterWith2 (set1:int list) (set2:int list) = 
    [0..set1.Length-1] 
    |> List.choose (fun i -> 
     match set2.[i] with 
     | 1 -> Some set1.[i] 
     | _ -> None) 

let filterWith3 (set1:int list) (set2:int list) = 
     List.foldBack2(fun x y acc -> if y=1 then x::acc else acc) set1 set2 [] 

open System.Linq 
let filterWith4 (set1:int list) (set2:int list) = 
     set1.Where(fun _ i -> set2.[i]=1) |> List.ofSeq 

filterWith2 set1 set2 |> printfn "%A" 
filterWith3 set1 set2 |> printfn "%A" 
filterWith4 set1 set2 |> printfn "%A" 

Print:

[2; 8; 10] 
[2; 8; 10] 
[2; 8; 10] 

https://dotnetfiddle.net/UaHuTk

+0

Спасибо - очень поучительный ... так много разных способов сделать то же самое в F #. .. любить это! – z0mbi3

+2

Мне все еще не хватает выражения List, которое было бы самым коротким: '[для x, y в List.zip set1 set2 do, если y <> 0, тогда выведите x]' – kaefer

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