Version française
Home     About     Download     Resources     Contact us    
Browse thread
Preferred Way to Split a List
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: skaller <skaller@u...>
Subject: Re: [Caml-list] Preferred Way to Split a 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