open Core.Std
open Biocaml_internal_utils
type t = (string * int * float) list
exception Bad of string
let raise_bad msg = raise (Bad msg)
let cmpsi (s1,i1,_) (s2,i2,_) = Pervasives.compare (s1,i1) (s2,i2)
let of_list l = List.sort ~cmp:cmpsi l
let to_list t = t
let of_chr_lists l =
let ans = List.map ~f:(fun (a,l) -> List.map ~f:(fun (b,c) -> a,b,c) l) l in
let ans = List.concat ans in
List.sort ~cmp:cmpsi ans
let npartition_exn ~eq l =
let open List in
let insertl ll a =
let rec loop prefix ll =
match ll with
| [] -> rev ([a]::prefix)
| l::ll ->
if eq a (hd_exn l)
then (rev ((a::l)::prefix)) @ ll
else loop (l::prefix) ll
in loop [] ll
in
map ~f:rev (fold_left ~f:insertl ~init:[] l)
let to_chr_lists t =
let eq (s1,_,_) (s2,_,_) = s1 = s2 in
let ll = npartition_exn ~eq t in
let ll =
List.map ~f:(fun l ->
let x, _, _ = List.hd_exn l in
x, List.map ~f:(fun (_,b,c) -> b,c) l) ll in
ll
let of_channel ?(chr_map=ident) ?(increment_bp=0) cin =
let parse_line' delim line =
match String.split line delim with
| [c; i; f] ->
chr_map c, int_of_string i + increment_bp, Float.of_string f
| _ -> raise_bad "ill-formed line"
in
let parse_line line =
try parse_line' '\t' line
with Bad _ ->
try parse_line' ' ' line
with Bad msg -> failwith msg
in
In_channel.input_lines cin
|> List.map ~f:parse_line
let of_file ?(chr_map=ident) ?(increment_bp=0) file =
try_finally_exn (of_channel ~chr_map ~increment_bp)
~fend:In_channel.close (open_in file)
let to_channel ?(chr_map=ident) ?(increment_bp=0) t cout =
let f (s,i,v) = fprintf cout "%s\t%d\t%f\n" (chr_map s) (i+increment_bp) v in
List.iter ~f t
let to_file ?(chr_map=ident) ?(increment_bp=0) t file =
try_finally_exn (to_channel ~chr_map ~increment_bp t)
~fend:Out_channel.close (open_out_safe file)