* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 7:58 ` Alain Frisch
@ 2007-10-29 9:34 ` Christophe Raffalli
2007-10-30 11:31 ` skaller
2007-10-30 12:30 ` David Allsopp
2007-10-30 11:15 ` skaller
1 sibling, 2 replies; 16+ messages in thread
From: Christophe Raffalli @ 2007-10-29 9:34 UTC (permalink / raw)
To: Alain Frisch; +Cc: skaller, caml-list
[-- Attachment #1.1: Type: text/plain, Size: 1043 bytes --]
Or
let split l n =
let rec aux acc l n =
if n = 0 then List.rev acc, l
else match l with
[] -> List.rev acc, []
| hd::l -> aux (hd::acc) l (n-1)
in aux [] l n
This is tail recursive, it does not use magic nor references
and keed the original ordering of the list.
Finally, I did in the past some testing comparing a tail-rec append or map
using magic and the composition of rev and rev-append or rev-map ...
There was no noticable difference, because the extra cost of
mutability (regarding the managment of the grey val list) compensate
the extra call to reverse.
So I think I would write split the way shown above if ordering matters.
Cheers,
Christophe
>
> Alain
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
[-- Attachment #1.2: Christophe.Raffalli.vcf --]
[-- Type: text/x-vcard, Size: 380 bytes --]
begin:vcard
fn:Christophe Raffalli
n:Raffalli;Christophe
org:LAMA (UMR 5127)
email;internet:Christophe.Raffalli@univ-savoie.fr
title;quoted-printable:Ma=C3=AEtre de conf=C3=A9rences
tel;work:+33 4 79 75 81 03
note;quoted-printable:Message sign=C3=A9 cryptographiquement avec pgp, la clef publique est sur=
subkeys.pgp.net
x-mozilla-html:TRUE
version:2.1
end:vcard
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Preferred Way to Split a List
@ 2007-10-29 23:33 Robert Fischer
2007-10-30 0:45 ` [Caml-list] " Matthew William Cox
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Robert Fischer @ 2007-10-29 23:33 UTC (permalink / raw)
To: caml-list
What is the preferred way to split a list into two, at an arbitrary
point? There's lots of ways you could do it, but I'm not sure if
there's a standard best practice for this.
~~ Robert.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-29 23:33 Preferred Way to Split a List Robert Fischer
@ 2007-10-30 0:45 ` Matthew William Cox
2007-10-30 13:18 ` Robert Fischer
2007-10-30 1:20 ` Julien Moutinho
2007-10-30 7:50 ` Jon Harrop
2 siblings, 1 reply; 16+ messages in thread
From: Matthew William Cox @ 2007-10-30 0:45 UTC (permalink / raw)
To: caml-list
[-- Attachment #1: Type: text/plain, Size: 550 bytes --]
On Mon, Oct 29, 2007 at 06:33:11PM -0500, Robert Fischer wrote:
> What is the preferred way to split a list into two, at an arbitrary point?
> There's lots of ways you could do it, but I'm not sure if there's a
> standard best practice for this.
That's the thing, there are lots of best ways. Which is the best depends
on what properties your list-splitter needs.
Do you need to preserve ordering in the sublists? Do they need to be
roughly equivalent lengths? Elaborating on these requirements will guide
your search.
Cheers,
Matt
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 827 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-29 23:33 Preferred Way to Split a List Robert Fischer
2007-10-30 0:45 ` [Caml-list] " Matthew William Cox
@ 2007-10-30 1:20 ` Julien Moutinho
2007-10-30 1:38 ` Karl Zilles
2007-10-30 5:46 ` skaller
2007-10-30 7:50 ` Jon Harrop
2 siblings, 2 replies; 16+ messages in thread
From: Julien Moutinho @ 2007-10-30 1:20 UTC (permalink / raw)
To: caml-list
On Mon, Oct 29, 2007 at 06:33:11PM -0500, Robert Fischer wrote:
> What is the preferred way to split a list into two, at an arbitrary point?
> There's lots of ways you could do it, but I'm not sure if there's a
> standard best practice for this.
Two answers for what they're worth:
# let split l f =
let rec aux =
function
| h::t as l ->
if f h then
let a,b = aux t in h::a,b
else [],l
| [] -> [],[]
in aux l;;
val split : 'a list -> ('a -> bool) -> 'a list * 'a list = <fun>
# split [1;2;3;4;5;6] ((>=) 4);;
- : int list * int list = ([1; 2; 3; 4], [5; 6])
(* may trash the given list but tail-recursive *)
# let magic_split l f =
let rec aux p =
function
| [] -> l,[]
| h::t as b ->
if f h then aux (Some b) t
else match p with None -> [],l
| Some p -> (Obj.magic p).(1) <- None; l,b
in aux None l;;
val magic_split : 'a list -> ('a -> bool) -> 'a list * 'a list = <fun>
# let l = [1;2;3;4;5;6];;
val l : int list = [1; 2; 3; 4; 5; 6]
# magic_split l ((>=) 4);;
- : int list * int list = ([1; 2; 3; 4], [5; 6])
# l;;
- : int list = [1; 2; 3; 4]
HTH,
Julien.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 1:20 ` Julien Moutinho
@ 2007-10-30 1:38 ` Karl Zilles
2007-10-30 5:46 ` skaller
1 sibling, 0 replies; 16+ messages in thread
From: Karl Zilles @ 2007-10-30 1:38 UTC (permalink / raw)
To: Julien Moutinho; +Cc: caml-list
Julien Moutinho wrote:
> (* may trash the given list but tail-recursive *)
> # let magic_split l f =
> let rec aux p =
> function
> | [] -> l,[]
> | h::t as b ->
> if f h then aux (Some b) t
> else match p with None -> [],l
> | Some p -> (Obj.magic p).(1) <- None; l,b
> in aux None l;;
> val magic_split : 'a list -> ('a -> bool) -> 'a list * 'a list = <fun>
> # let l = [1;2;3;4;5;6];;
> val l : int list = [1; 2; 3; 4; 5; 6]
> # magic_split l ((>=) 4);;
> - : int list * int list = ([1; 2; 3; 4], [5; 6])
> # l;;
> - : int list = [1; 2; 3; 4]
Wow, this looks like a horrible idea! You're modifying a non-mutable
data structure and using object magic. This leads to madness:
# let test () = magic_split [1; 2; 3; 4; 5; 6] ((>=) 4);;
val test : unit -> int list * int list = <fun>
# test ();;
- : int list * int list = ([1; 2; 3; 4], [5; 6])
# test ();;
- : int list * int list = ([1; 2; 3; 4], [])
I'm sure you're aware of this, but to suggest this as an answer to his
question...
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 1:20 ` Julien Moutinho
2007-10-30 1:38 ` Karl Zilles
@ 2007-10-30 5:46 ` skaller
2007-10-30 7:58 ` Alain Frisch
1 sibling, 1 reply; 16+ messages in thread
From: skaller @ 2007-10-30 5:46 UTC (permalink / raw)
To: Julien Moutinho; +Cc: caml-list
On Tue, 2007-10-30 at 02:20 +0100, Julien Moutinho wrote:
> On Mon, Oct 29, 2007 at 06:33:11PM -0500, Robert Fischer wrote:
> > What is the preferred way to split a list into two, at an arbitrary point?
> > There's lots of ways you could do it, but I'm not sure if there's a
> > standard best practice for this.
>
> Two answers for what they're worth:
Ouch. A simpler way is:
let split ls n = let rec aux inp out n =
if n = 0 then unsafe_rev_cat out inp
else match inp with
| [] -> unsafe_rev_cat out []
| h :: t -> aux t (h::out) (n-1)
in aux ls [] n
Here 'unsafe_rev_cat' uses magic to reverse a list in place
and tack the tail onto the end.
However this isn't the fastest way. The fastest way is:
let split ls n =
let out = magic_list() in
let rec aux inp n =
if n = 0 then magic_cat out inp
else match inp with
| [] -> ()
| h :: t -> magic_append h out; aux t (n-1)
in
aux ls n;
list_of out
Here the magic list is the usual list data structure PLUS a pointer
to the last element allowing O(1) append. This is of course a mutable
data structure. All the operations here can be implemented without
Obj.magic, however it's much faster WITH Obj.magic: by using a
magic list structure identical to an actual list, the 'list_of'
function becomes a typecast.
A similar code uses a reversed ordinary list for the temporary,
and then reverses it inplace (safe because it is a temporary)
and tacks the tail on. Felix uses that algorithm in its standard
library, however the one actually coded above is optimal (it isn't
possible to do it any faster).
Note the function above is purely functional (mutations are
isolated to the implementation) and does not itself use any
unsafe features (but the magic implementation is unsafe,
so it should be put in a library to limit bugs and
implementation dependencies).
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-29 23:33 Preferred Way to Split a List Robert Fischer
2007-10-30 0:45 ` [Caml-list] " Matthew William Cox
2007-10-30 1:20 ` Julien Moutinho
@ 2007-10-30 7:50 ` Jon Harrop
2007-10-30 13:20 ` Robert Fischer
2 siblings, 1 reply; 16+ messages in thread
From: Jon Harrop @ 2007-10-30 7:50 UTC (permalink / raw)
To: caml-list
On Monday 29 October 2007 23:33, Robert Fischer wrote:
> What is the preferred way to split a list into two, at an arbitrary
> point? There's lots of ways you could do it, but I'm not sure if
> there's a standard best practice for this.
I tend to write a combinator that nests an arbitrary number of function
applications:
# let rec nest n f x =
if n=0 then x else nest (n-1) f (f x);;
val nest : int -> ('a -> 'a) -> 'a -> 'a = <fun>
and then apply this to a function that moves head elements:
# let aux = function
| front, h::back -> h::front, back
| _ -> invalid_arg "aux";;
val aux : 'a list * 'a list -> 'a list * 'a list = <fun>
Then I write a "chop" function in terms of those two:
# let chop n list =
nest n aux ([], list);;
val chop : int -> 'a list -> 'a list * 'a list = <fun>
For example, splitting after the fourth element:
# chop 4 [1;2;3;4;5;6;7;8;9];;
- : int list * int list = ([4; 3; 2; 1], [5; 6; 7; 8; 9])
Note that the front list is reversed.
PS: Ignore any responses that even mention Obj.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/products/?e
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 5:46 ` skaller
@ 2007-10-30 7:58 ` Alain Frisch
2007-10-29 9:34 ` Christophe Raffalli
2007-10-30 11:15 ` skaller
0 siblings, 2 replies; 16+ messages in thread
From: Alain Frisch @ 2007-10-30 7:58 UTC (permalink / raw)
To: skaller; +Cc: Julien Moutinho, caml-list
skaller wrote:
> The fastest way is:
How can you be so sure? Do you have a proof or some intuitive argument?
Or maybe you tried all the possible other implementations? The following
should not be that much slower (I did not try it, though, and of course,
it is not tail-rec):
let split l n =
let l2 = ref [] in
let rec aux l n =
if n = 0 then (l2 := l; [])
else match l with
| [] -> []
| hd :: tl -> hd :: (aux tl (n - 1))
in
let l1 = aux l n in
(l1, !l2)
Alain
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 7:58 ` Alain Frisch
2007-10-29 9:34 ` Christophe Raffalli
@ 2007-10-30 11:15 ` skaller
2007-10-30 13:05 ` Brian Hurt
1 sibling, 1 reply; 16+ messages in thread
From: skaller @ 2007-10-30 11:15 UTC (permalink / raw)
To: Alain Frisch; +Cc: Julien Moutinho, caml-list
On Tue, 2007-10-30 at 08:58 +0100, Alain Frisch wrote:
> skaller wrote:
> > The fastest way is:
>
> How can you be so sure?
Why do I need to be something naturally impossible?
Certainty isn't even possible in the presence of a proof.
The fact here is I made a complete mess!
My algorithm doesn't meet the specification. LOL!
It doesn't split a list in two dang it! It actually
splits it in two then recombines the result and
returns the original list! :)
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-29 9:34 ` Christophe Raffalli
@ 2007-10-30 11:31 ` skaller
2007-10-30 12:30 ` David Allsopp
1 sibling, 0 replies; 16+ messages in thread
From: skaller @ 2007-10-30 11:31 UTC (permalink / raw)
To: Christophe Raffalli; +Cc: Alain Frisch, caml-list
On Mon, 2007-10-29 at 10:34 +0100, Christophe Raffalli wrote:
> Or
>
> let split l n =
> let rec aux acc l n =
> if n = 0 then List.rev acc, l
> else match l with
> [] -> List.rev acc, []
> | hd::l -> aux (hd::acc) l (n-1)
> in aux [] l n
>
> This is tail recursive, it does not use magic nor references
> and keed the original ordering of the list.
Yes, but it double handles the head needlessly. Ignoring
the interesting observation you make below, this would
be expected to transfer head memory twice into the cache,
when once would suffice.
> Finally, I did in the past some testing comparing a tail-rec append or map
> using magic and the composition of rev and rev-append or rev-map ...
> There was no noticable difference, because the extra cost of
> mutability (regarding the managment of the grey val list) compensate
> the extra call to reverse.
However, you raise here an important issue not covered well anywhere:
when you have a garbage collection, the effect of some operation
should include not just the local algorithmic considerations
but also the cost of the garbage collection.
In the equivalent Felix code, there is no issue with write
barriers because Felix collector doesn't use them, so mutations
don't incur any cost. OTOH allocations are expensive.
Now, back to collectors .. the append is a special.
The mutations in the append are not mutations, but deferred
initialisations, that is, the write operation is guaranteed
to be replacing a NULL pointer.
Overwriting of NULL pointers is already possible in functional
coding without it implying mutation.
So one might imagine a collector with a minor and major heap,
in which the major heap requires special handling for mutations.
However the rule for moving an object out of the minor heap
is that the object must be fully initialised. (all pointers
in the block are non-null).
In that design (I have no idea if it is viable!) the performance
might be different for the 'append' and other mutations.
The bottom line is that a good point is made that the
usual fine detail performance analysis doesn't apply to
a garbage collected language.. thanks for pointing this out!
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [Caml-list] Preferred Way to Split a List
2007-10-29 9:34 ` Christophe Raffalli
2007-10-30 11:31 ` skaller
@ 2007-10-30 12:30 ` David Allsopp
2007-10-30 15:03 ` Christophe Raffalli
1 sibling, 1 reply; 16+ messages in thread
From: David Allsopp @ 2007-10-30 12:30 UTC (permalink / raw)
To: caml-list
Christophe Raffalli wrote:
> let split l n =
> let rec aux acc l n =
> if n = 0 then List.rev acc, l
> else match l with
> [] -> List.rev acc, []
> | hd::l -> aux (hd::acc) l (n-1)
> in aux [] l n
I'd go one stage further and use Obj.magic to eliminate the List.rev calls
(cf. ExtList.List in ExtLib). I'm sensibly wary of using Obj.magic in
general but find it acceptable here because its use is hidden within the
function (you are constructing a new list anyway, you just use Obj.magic to
allow tail-consing instead) - and there is no risk of "entertaining" side
effects (cf. John's earlier email!). I've got tail-consing wrapped in a few
extra functions in List so that this would become:
let split l n =
let acc = List.tlempty ()
in
let rec aux l n =
if n = 0 then (List.tlresult acc, l)
else match l with
[] -> (List.tlresult acc, [])
| hd::l -> List.tlcons hd acc; aux l (n-1)
in
aux l n
David
PS List.tlempty: returns a new, empty tail-consing list
List.tlcons x tlist: adds x to the end of the given tlist and returns
the same tlist pointer
List.tlresult tlist: casts an 'a tlist to an 'a list - and marks the
tlist as "exported", preventing future tail-consing
(which would violate the semantics of O'Caml 'a
lists)
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 11:15 ` skaller
@ 2007-10-30 13:05 ` Brian Hurt
0 siblings, 0 replies; 16+ messages in thread
From: Brian Hurt @ 2007-10-30 13:05 UTC (permalink / raw)
To: skaller; +Cc: Alain Frisch, caml-list
[-- Attachment #1: Type: text/plain, Size: 1543 bytes --]
skaller wrote:
>On Tue, 2007-10-30 at 08:58 +0100, Alain Frisch wrote:
>
>
>>skaller wrote:
>>
>>
>>>The fastest way is:
>>>
>>>
>>How can you be so sure?
>>
>>
>
>Why do I need to be something naturally impossible?
>Certainty isn't even possible in the presence of a proof.
>
>The fact here is I made a complete mess!
>
>My algorithm doesn't meet the specification. LOL!
>It doesn't split a list in two dang it! It actually
>splits it in two then recombines the result and
>returns the original list! :)
>
>
>
>
Just so people know, Obj.magic is not necessary here:
let take n lst =
let rec loop accum n lst =
if n == 0 then
List.rev accum
else match lst with
| x :: xs -> loop (x :: accum) (n - 1) xs
| [] -> List.rev accum
in
if n < 0 then
invalid_arg "Negative argument to List.take"
else
loop [] n lst
;;
let rec drop n lst =
if n < 0 then
invalid_arg "Negative argument to List.drop"
else if n == 0 then
lst
else match lst with
| _ :: xs -> drop (n - 1) xs
| [] -> []
;;
I'd also take a look at the standard library functions List.filter and
List.partition. With their standard, Obj.magic-less, implementations.
If the list is long enough that the extra overhead of calling List.rev
is a problem, I'd recommend using a better data structure than a list.
I'm fond of tree-based "functional arrays", which allow for splitting
them in O(log N), instead of O(N). We're clock cycle tuning bubble sort
here.
Brian
[-- Attachment #2: Type: text/html, Size: 2603 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 0:45 ` [Caml-list] " Matthew William Cox
@ 2007-10-30 13:18 ` Robert Fischer
2007-11-03 3:06 ` Nathaniel Gray
0 siblings, 1 reply; 16+ messages in thread
From: Robert Fischer @ 2007-10-30 13:18 UTC (permalink / raw)
To: caml-list
> Do you need to preserve ordering in the sublists?
>
Yes.
> Do they need to be roughly equivalent lengths?
No -- the head list will probably be shorter than the tail list.
~~ Robert.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 7:50 ` Jon Harrop
@ 2007-10-30 13:20 ` Robert Fischer
0 siblings, 0 replies; 16+ messages in thread
From: Robert Fischer @ 2007-10-30 13:20 UTC (permalink / raw)
To: caml-list
[-- Attachment #1: Type: text/html, Size: 1591 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 12:30 ` David Allsopp
@ 2007-10-30 15:03 ` Christophe Raffalli
0 siblings, 0 replies; 16+ messages in thread
From: Christophe Raffalli @ 2007-10-30 15:03 UTC (permalink / raw)
To: David Allsopp; +Cc: caml-list
[-- Attachment #1: Type: text/plain, Size: 3859 bytes --]
David Allsopp a écrit :
> Christophe Raffalli wrote:
>> let split l n =
>> let rec aux acc l n =
>> if n = 0 then List.rev acc, l
>> else match l with
>> [] -> List.rev acc, []
>> | hd::l -> aux (hd::acc) l (n-1)
>> in aux [] l n
>
> let split l n =
> let acc = List.tlempty ()
> in
> let rec aux l n =
> if n = 0 then (List.tlresult acc, l)
> else match l with
> [] -> (List.tlresult acc, [])
> | hd::l -> List.tlcons hd acc; aux l (n-1)
> in
> aux l n
>
>
My point in my second last post was that in practice, for OCaml, the
second code is not much faster than the first ...
All this forced me to redo the testing : the details are bellow, but
list_split with rev wins for small list, the dirty thing with set_field
wins for big lists and the transition is between length 10000 and 100000.
Overall the difference is small.
Remark: the result might differ a lot for map if the mapped function does allocate memory ...
then there should almost no difference ...
So I would advice not to use Obj.set_field in this case ...
(* module for lists that can be constructed by both end *)
module Tlist = struct
type 'a tlist = 'a list * 'a list
(* a fake value for the tail of a list *)
let rec dummy_tlist = Obj.magic 0::dummy_tlist
let empty = [], []
let tailcons tl a =
match tl with
[], [] -> let tl = a :: dummy_tlist in (tl, tl)
| (_::_ as s), (_::dl as e) when dl == dummy_tlist ->
let e' = a::dummy_tlist in
Obj.set_field (Obj.repr e) 1 (Obj.repr e');
s, e'
| _ -> raise (Invalid_argument "Tlist.tail_cons")
let cons a tl =
match tl with
[], [] -> let tl = a :: dummy_tlist in (tl, tl)
| (_::_ as s), (_::dl as e) when dl == dummy_tlist ->
a::s, e
| _ -> raise (Invalid_argument "Tlist.cons")
(* this must be the final call to transform a 'a tlist into a list *)
let append tl l =
match tl with
[], [] -> l
| (_::_ as s), (_::dl as e) when dl == dummy_tlist ->
Obj.set_field (Obj.repr e) 1 (Obj.repr l);
s
| _ -> raise (Invalid_argument "Tlist.append")
end
(* the two versions of split *)
let split_with_rev l n =
let rec aux acc l n =
if n = 0 then List.rev acc, l
else match l with
[] -> List.rev acc, []
| hd::l -> aux (hd::acc) l (n-1)
in aux [] l n
let split_with_tlist l n =
let rec aux acc l n =
if n = 0 then (Tlist.append acc [], l)
else match l with
[] -> Tlist.append acc [], []
| hd::l -> aux (Tlist.tailcons acc hd) l (n-1)
in
aux Tlist.empty l n
(* code for testing *)
let rec build_list n =
let rec aux acc n =
if n = 0 then acc else aux (n::acc) (n-1)
in
aux [] n
let test_tlist n p =
for i = 1 to n do
ignore (split_with_tlist (build_list (2*p)) p)
done
let test_rev n p =
for i = 1 to n do
ignore (split_with_rev (build_list (2*p)) p)
done
let _ = test_tlist 10 1000000
(*
result:
test_tlist 10000000 10 : 3.1s
test_rev 10000000 10 : 2.6s
test_tlist 100000 1000 : 8.8s
test_rev 100000 1000 : 6.9s
test_tlist 100 100000 : 5.9s
test_rev 100 100000 : 7.4s
test_tlist 10 1000000 : 6.2s
test_rev 10 1000000 : 7.9s
*)
--
Christophe Raffalli
Universite de Savoie
Batiment Le Chablais, bureau 21
73376 Le Bourget-du-Lac Cedex
tel: (33) 4 79 75 81 03
fax: (33) 4 79 75 87 42
mail: Christophe.Raffalli@univ-savoie.fr
www: http://www.lama.univ-savoie.fr/~RAFFALLI
---------------------------------------------
IMPORTANT: this mail is signed using PGP/MIME
At least Enigmail/Mozilla, mutt or evolution
can check this signature. The public key is
stored on www.keyserver.net
---------------------------------------------
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Caml-list] Preferred Way to Split a List
2007-10-30 13:18 ` Robert Fischer
@ 2007-11-03 3:06 ` Nathaniel Gray
0 siblings, 0 replies; 16+ messages in thread
From: Nathaniel Gray @ 2007-11-03 3:06 UTC (permalink / raw)
To: Robert Fischer; +Cc: caml-list
On Oct 30, 2007 6:18 AM, Robert Fischer <robert@fischerventure.com> wrote:
>
> > Do you need to preserve ordering in the sublists?
> >
> Yes.
> > Do they need to be roughly equivalent lengths?
> No -- the head list will probably be shorter than the tail list.
Hmm...
let fast_list_splitter = function
| h :: t -> [h], t
| [] -> [], [] (* Or maybe raise an exception? *)
Or if you're really shooting for speed:
let golly_it's_fast_list_splitter lst = [], lst
I win. Seriously, you must have *some* further constraints!
Cheers,
-n8
--
>>>-- Nathaniel Gray -- Caltech Computer Science ------>
>>>-- Mojave Project -- http://mojave.cs.caltech.edu -->
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2007-11-03 3:07 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-29 23:33 Preferred Way to Split a List Robert Fischer
2007-10-30 0:45 ` [Caml-list] " Matthew William Cox
2007-10-30 13:18 ` Robert Fischer
2007-11-03 3:06 ` Nathaniel Gray
2007-10-30 1:20 ` Julien Moutinho
2007-10-30 1:38 ` Karl Zilles
2007-10-30 5:46 ` skaller
2007-10-30 7:58 ` Alain Frisch
2007-10-29 9:34 ` Christophe Raffalli
2007-10-30 11:31 ` skaller
2007-10-30 12:30 ` David Allsopp
2007-10-30 15:03 ` Christophe Raffalli
2007-10-30 11:15 ` skaller
2007-10-30 13:05 ` Brian Hurt
2007-10-30 7:50 ` Jon Harrop
2007-10-30 13:20 ` Robert Fischer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox