TierTwo
TierTwo

Reputation: 133

How to modify a list of lists if it contains x or -x?

I'm trying to modify a list of lists with certain conditions, if a nested list contains x, I'd like to remove that list from the list, if a nested list contains -x, I'd like to remove -x from that list while still keeping the said list. Finally, if the nested list doesn't contain x or -x, I'd keep it.

So far this is what I've tried, I don't really get why it doesn't work as intented...

let rec simplify i clauses =
  match clauses with
  | [] -> []
  | x::y -> 
      if (List.mem i x) then 
        [] @ simplify i y 
      else if (List.mem (-i) x) then 
        List.filter (fun x -> x != -i) x @ simplify i y 
      else 
        [x];;

The expected results would be that:

simplify (-1) [[-1;2];[-1;7];[-2;1];[-2;3];[-3;2];[-3;4];[-4;5];[-4;15];[-5;2];[-5;4];[-6;5];[-7;1];[-7;8];[-7;6];[-8;7];[-8;9];[-8;10];[-9;8];[-10;8];[-10;11];[-10;12];[-11;9];[-11;10];[-12;6];[-12;10];[-12;13];[-12;15];[-13;11];[-14;13];[-14;15];[-15;12];[1];[-14]]
;;
- : int list list =
[[-14]; []; [-15; 12]; [-14; 15]; [-14; 13]; [-13; 11]; [-12; 15]; [-12; 13];
 [-12; 10]; [-12; 6]; [-11; 10]; [-11; 9]; [-10; 12]; [-10; 11]; [-10; 8];
 [-9; 8]; [-8; 10]; [-8; 9]; [-8; 7]; [-7; 6]; [-7; 8]; [-7]; [-6; 5]; 
 [-5; 4]; [-5; 2]; [-4; 15]; [-4; 5]; [-3; 4]; [-3; 2]; [-2; 3]; [-2]]

Whereas the actual results are:

simplifie_aux (-1) [[-1;2];[-1;7];[-2;1];[-2;3];[-3;2];[-3;4];[-4;5];[-4;15];[-5;2];[-5;4];[-6;5];[-7;1];[-7;8];[-7;6];[-8;7];[-8;9];[-8;10];[-9;8];[-10;8];[-10;11];[-10;12];[-11;9];[-11;10];[-12;6];[-12;10];[-12;13];[-12;15];[-13;11];[-14;13];[-14;15];[-15;12];[1];[-14]]
;;
- : int list list = [[-2]; [-2; 3]]

Thanks.

Upvotes: 0

Views: 73

Answers (2)

Chris
Chris

Reputation: 36620

This seems like an ideal place to utilize List.filter_map as you are trying to perform both filtering and mapping at the same time.

# [[-1; 2]; [-1; 7]; [-2; 1]; [-2; 3]; [-3; 2]; [-3; 4]; 
   [-4; 5]; [-4; 15]; [-5; 2]; [-5; 4]; [-6; 5]; [-7; 1]; 
   [-7; 8]; [-7; 6]; [-8; 7]; [-8; 9]; [-8; 10]; [-9; 8];
   [-10; 8]; [-10; 11]; [-10; 12]; [-11; 9]; [-11; 10];
   [-12; 6]; [-12; 10]; [-12; 13]; [-12; 15]; [-13; 11];
   [-14; 13]; [-14; 15]; [-15; 12]; [1]; [-14]]
  |> List.filter_map (fun lst -> 
       if List.mem ~-1 lst then None 
       else if List.mem 1 lst then Some (List.filter ((<>) 1) lst) 
       else Some lst
     );;
- : int list list =
[[-2]; [-2; 3]; [-3; 2]; [-3; 4]; [-4; 5]; [-4; 15]; [-5; 2]; [-5; 4]; 
 [-6; 5]; [-7]; [-7; 8]; [-7; 6]; [-8; 7]; [-8; 9]; [-8; 10]; [-9; 8];
 [-10; 8]; [-10; 11]; [-10; 12]; [-11; 9]; [-11; 10]; [-12; 6]; [-12; 10];
 [-12; 13]; [-12; 15]; [-13; 11]; [-14; 13]; [-14; 15]; [-15; 12]; []; 
 [-14]]

Upvotes: 0

Rorschach
Rorschach

Reputation: 32446

In your code, it appears you should be recursing in the final else [x] case as well. I would rewrite it as a fold, however, since you are dropping (some) empty lists from your expected output, eg.

let simplify i clauses = 
  let f acc lst =
    if List.mem i lst then acc
    else [List.filter (fun x -> x != -i) lst] @ acc
  in List.fold_left f [] clauses

(* - : int list list =
   [[-14]; []; [-15; 12]; [-14; 15]; ... ] *)

Upvotes: 0

Related Questions