module List =
/// A map function with additional state
let mapp f state lst =
let rec mapp_aux f state lst acc =
if List.is_empty lst then
List.rev acc
else
let elem, state = f (List.hd lst) state
mapp_aux f state (List.tl lst) (elem :: acc)
mapp_aux f state lst []
let split elem acc =
match acc with
| [] -> [[elem]]
| (1::_)::_ -> [elem] :: acc
| h::t -> (elem :: h) :: t
let next_char c =
char (int c + 1)
let rename elem (hash, ch) =
if hash |> Map.mem elem then
(hash.[elem], (hash, ch))
else
(ch, (hash |> Map.add elem ch, next_char ch))
let a = [1;6;7;8;1;8;7;4;3;2;1;6;7;8;1;6;5;1;9;1;6;5;1;6;7;8;1;9;1;9;1;6;7;8;1;3]
let b = List.fold_right split a [] |> List.mapp rename (Map.empty, 'A')
// b = [A; B; A; C; D; C; A; D; D; A; E]
Here is my solution.
First, use a standard sequence-expression with state to accumulate the partial subsequences. Note this portion of the algorithm is, I believe, just as clea in either imperative or functional programming. The key thing is to abstract and encapsulate the imperative programming into a lovely reusable functional programming sequence processor. The F# "Seq" library is full of lots of examples like this.
Next, given an initial element "n" and a sequence "s", the analysis is straight forward. Note the use of Seq.distinct to ensure no repeats.
This is OK, but loses information, e.g. what do A and B mean in the result??? This leads is a perfect example of F# object oriented programming to return multiple interesting results from an analysis and give those results good names:
Now run
First, use a standard sequence-expression with state to accumulate the partial subsequences. Note this portion of the algorithm is, I believe, just as clea in either imperative or functional programming. The key thing is to abstract and encapsulate the imperative programming into a lovely reusable functional programming sequence processor. The F# "Seq" library is full of lots of examples like this.
/// Return all the subsequences starting with a given character. Also return any initial
/// sequence not starting with that character. Do this by keeping an internal accumulator and publishing from it
let SequencesStartingWith n (s:seq<_>) =
seq { use ie = s.GetEnumerator()
let acc = new ResizeArray<_>()
while ie.MoveNext() do
let x = ie.Current
if x = n && acc.Count > 0 then
yield ResizeArray.to_list acc
acc.Clear()
acc.Add x
if acc.Count > 0 then
yield ResizeArray.to_list acc }
Next, given an initial element "n" and a sequence "s", the analysis is straight forward. Note the use of Seq.distinct to ensure no repeats.
let analyze n s =
let subsequences = SequencesStartingWith n s |> Seq.distinct |> Seq.to_list
let subsequenceToName = subsequences |> List.mapi (fun i x -> x,char (int 'A' + i)) |> Map.of_list
let result = subsequences |> List.map (fun x -> subsequenceToName.[x])
result
This is OK, but loses information, e.g. what do A and B mean in the result??? This leads is a perfect example of F# object oriented programming to return multiple interesting results from an analysis and give those results good names:
/// Do the subsequence analysis on an input sequence and return an object revealing the
/// forward mapping table 'A' to [1;3;4], the backward mapping table '[1;3;4]' to 'A',
/// the overall result, and the actual unique subsequences found.
type SequenceMarkup<'a>(marker,s:seq<'a>) =
let subsequences = SequencesStartingWith marker s |> Seq.distinct |> Seq.to_list
let mapping = subsequences |> List.mapi (fun i x -> x,char (int 'A' + i))
let subsequenceToName = mapping |> Map.of_list
let result = subsequences |> List.map (fun x -> subsequenceToName.[x])
let nameToSubsequence = mapping |> List.map (fun (x,y) -> (y,x)) |> Map.of_list
/// Get the name corresponding to a particular subsequence
member x.NameForSubsequence(subsequence) = subsequenceToName.TryFind(subsequence)
/// Get the subsequence corresponding to a particular name
member x.SubsequenceForName(name) = nameToSubsequence.TryFind(name)
/// Get the subsequence corresponding to a particular name
member x.Subsequences = subsequences
/// Get the input list with subsequences replaced by names
member x.Result = result
Now run
let markup = SequenceMarkup(1,[1; 6; 7; 8; 1; 8; 7; 4; 3; 2; 1; 6; 7; 8; 1; 6; 5; 1; 9; 1; 6; 5; 1; 6; 7; 8; 1; 9; 1; 9; 1; 6; 7; 8; 1; 3; ]) markup.Result markup.Subsequences markup.SubsequenceForName 'A'
Hi Don,
how should your previous code be modified in order to use the Equality and Comparison Constraints?
thanks!
how should your previous code be modified in order to use the Equality and Comparison Constraints?
thanks!
I came up with the following code,
which seems working. However, I don't know how to generate fresh names, but I guess reflection can do that.
>let trans l = let h = HashMultiMap.Create() and i = ref 64 in let _,l' = List.fold_right (fun x (tmp,acc) -> if x=1 then [],(x::tmp)::acc else (x::tmp),acc) l ([],[]) in List.map (fun x -> match h.TryFind x with Some v -> v | None -> incr i; let c = char_of_int !i in h.Add(x,c); c) l';; val trans : int list -> char list >trans [1; 6; 7; 8; 1; 8; 7; 4; 3; 2; 1; 6; 7; 8; 1; 6; 5; 1; 9; 1; 6; 5; 1; 6; 7; 8; 1; 9; 1; 9; 1; 6; 7; 8; 1; 3];; val it : char list = ['A'; 'B'; 'A'; 'C'; 'D'; 'C'; 'A'; 'D'; 'D'; 'A'; 'E']
which seems working. However, I don't know how to generate fresh names, but I guess reflection can do that.
Thank you (aChrisSmith, gneverov and code17)
I think the functional programming is not really obvious.
My impression is that whenever we have to find a trick.
But once found, the code is short and elegant.
The imperative programming seems easier to understand.
But in this case, it seems to me that this would be very difficult to do in C++ or C#.
I think the functional programming is not really obvious.
My impression is that whenever we have to find a trick.
But once found, the code is short and elegant.
The imperative programming seems easier to understand.
But in this case, it seems to me that this would be very difficult to do in C++ or C#.
Hi jonaas,
A similar problem was discussed in this thread [link:cs.hubfs.net]. A solution to your problem build upon the solution from this thread is.
Using a set to do the renaming of the sublists is convenient but not terribly efficient. If that's a problem you might want to do something like building a tree to perform list equality tests.
Here's the relevant code from the other thread.
A similar problem was discussed in this thread [link:cs.hubfs.net]. A solution to your problem build upon the solution from this thread is.
let sublists = f ((=) 1) input let unique xs = xs |> Set.of_list |> Set.to_list let answer = let lookup = unique sublists List.map (fun x -> List.find_index ((=) x) lookup) sublists
Using a set to do the renaming of the sublists is convenient but not terribly efficient. If that's a problem you might want to do something like building a tree to perform list equality tests.
Here's the relevant code from the other thread.
let f p xs =
let f xs =
match xs with
| [] -> None
| x::xs' -> let ys, zs = break p xs'
Some (x::ys, zs)
unfold f xs
let unfold f x =
let rec unfold' x acc =
match f x with
| None -> List.rev acc
| Some (a, x') -> unfold' x' (a::acc)
unfold' x []
let break p xs =
let rec break' xs acc =
match xs with
| [] -> List.rev acc, []
| x::_ when p x -> List.rev acc, xs
| x::xs' -> break' xs' (x::acc)
break' xs []You can break this down into three different problems:
1. Converting the input into a set of sub lists each begining with the number 1
2. Itterating through the first list and describing it as a sequence of sub lists
3. Printing out the resutls
Here is a quick and dirty solution, I'm sure you can make it more efficent :)
I'll try to blog about this next week to explain how it all works. Nice problem :)
1. Converting the input into a set of sub lists each begining with the number 1
2. Itterating through the first list and describing it as a sequence of sub lists
3. Printing out the resutls
Here is a quick and dirty solution, I'm sure you can make it more efficent :)
#light
let input = [1; 6; 7; 8; 1; 8; 7; 4; 3; 2; 1; 6; 7; 8; 1; 6; 5; 1; 9; 1; 6; 5; 1; 6; 7; 8; 1; 9; 1; 9; 1; 6; 7; 8; 1; 3]
printfn "input = %A" input
let foldFunc i acc =
if acc = [] then
[ [ i ] ]
elif List.hd (List.hd acc) = 1 then
[ i ] :: acc
else
(i :: (List.hd acc)) :: (List.tl acc)
// Break it down into sub lists starting with 1
let orgSubLists = List.fold_right foldFunc input []
// Make them unique..
let subLists = orgSubLists |> Set.of_list |> Set.to_list
printfn "sub lists = %A" subLists
// Now reduce the origional
let reduceList list subLists =
let rec reduceListr list subLists seenSoFar resultsSoFar =
if list = [] then
resultsSoFar
else
let result = List.tryfind_index (fun subList -> subList = seenSoFar) subLists
if Option.is_none result then
reduceListr (List.tl list) subLists (seenSoFar @ [List.hd list]) resultsSoFar
else
reduceListr list subLists [] (resultsSoFar @ [Option.get result])
reduceListr list subLists [] []
let reducedList = reduceList input subLists
printfn "reduced list (indexes) = %A" reducedList
// Now make the results meaningful...
List.iteri (fun i subList -> printfn "%c = %A" (char (65 + i)) subList) subLists
let letteredAnswer = List.map (fun i -> char (65 + i)) reducedList
printfn "Answer = %A" letteredAnswer
(* Output
input = [1; 6; 7; 8; 1; 8; 7; 4; 3; 2; 1; 6; 7; 8; 1; 6; 5; 1; 9; 1; 6; 5; 1; 6; 7; 8; 1;
9; 1; 9; 1; 6; 7; 8; 1; 3]
sub lists = [[1; 3]; [1; 6; 5]; [1; 6; 7; 8]; [1; 8; 7; 4; 3; 2]; [1; 9]]
reduced list (indexes) = [2; 3; 2; 1; 4; 1; 2; 4; 4; 2]
A = [1; 3]
B = [1; 6; 5]
C = [1; 6; 7; 8]
D = [1; 8; 7; 4; 3; 2]
E = [1; 9]
Answer = ['C'; 'D'; 'C'; 'B'; 'E'; 'B'; 'C'; 'E'; 'E'; 'C']
Press any key to continue . . .
*)
I'll try to blog about this next week to explain how it all works. Nice problem :)
Thank you
Finally it does not seem obvious.
But I began to functional programming (F#)
I thought a code without "if ... then .. else ...".
I look at everything.
The "reduceList" is ... (euh!) ... mysterious
Again thank you.
Finally it does not seem obvious.
But I began to functional programming (F#)
I thought a code without "if ... then .. else ...".
I look at everything.
The "reduceList" is ... (euh!) ... mysterious
Again thank you.
Topic tags
- f# × 3663
- compiler × 263
- functional × 199
- websharper × 120
- c# × 119
- classes × 96
- web × 94
- book × 84
- .net × 82
- async × 72
- parallel × 43
- server × 43
- parsing × 41
- testing × 41
- asynchronous × 30
- monad × 28
- ocaml × 26
- tutorial × 26
- haskell × 25
- workflows × 22
- html × 21
- linq × 21
- introduction × 19
- silverlight × 19
- wpf × 19
- fpish × 18
- collections × 14
- pipeline × 14
- templates × 12
- monads × 11
- opinion × 10
- reactive × 10
- plugin × 9
- scheme × 9
- sitelets × 9
- solid × 9
- basics × 8
- concurrent × 8
- deployment × 8
- how-to × 8
- python × 8
- complexity × 7
- javascript × 6
- jquery × 6
- lisp × 6
- real-world × 6
- workshop × 6
- xaml × 6
- conference × 5
- dsl × 5
- java × 5
- metaprogramming × 5
- ml × 5
- scala × 5
- visual studio × 5
- formlets × 4
- fsi × 4
- lift × 4
- sql × 4
- teaching × 4
- alt.net × 3
- aml × 3
- enhancement × 3
- list × 3
- reflection × 3
- type provider × 3
- blog × 2
- compilation × 2
- computation expressions × 2
- corporate × 2
- courses × 2
- cufp × 2
- enterprise × 2
- entity framework × 2
- erlang × 2
- events × 2
- f# interactive × 2
- fsc × 2
- google maps × 2
- html5 × 2
- http × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- kendo × 2
- keynote × 2
- mvc × 2
- numeric × 2
- obfuscation × 2
- oop × 2
- packaging × 2
- pattern matching × 2
- pipelines × 2
- rx × 2
- script × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- type × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- addin × 1
- agents × 1
- agile × 1
- alter session × 1
- android × 1
- anonymous object × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net mvc × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- b-tree × 1
- bistro × 1
- bug × 1
- camtasia studio × 1
- canvas × 1
- class × 1
- client × 1
- clojure × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- combinator × 1
- confirm × 1
- constructor × 1
- continuation-passing style × 1
- coords × 1
- coursera × 1
- csla × 1
- css × 1
- current_schema × 1
- data × 1
- database × 1
- declarative × 1
- delete × 1
- dhtmlx × 1
- discriminated union × 1
- distance × 1
- docs × 1
- documentation × 1
- dol × 1
- domain × 1
- du × 1
- duf-101 × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- error × 1
- etw × 1
- euclidean × 1
- event × 1
- example × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- fantomas × 1
- fear × 1
- float × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- function × 1
- functional style × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- google × 1
- group × 1
- hash × 1
- history × 1
- hosting × 1
- httpcontext × 1
- https × 1
- hubfs × 1
- ie 8 × 1
- if-doc × 1
- inheritance × 1
- installer × 1
- interpreter × 1
- io × 1
- ios × 1
- ipad × 1
- kendochart × 1
- kendoui × 1
- learning × 1
- licensing × 1
- macro × 1
- macros × 1
- maps × 1
- markup × 1
- marshal × 1
- math × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- multidimensional × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- nested × 1
- nested loops × 1
- node × 1
- object relation mapper × 1
- object-oriented × 1
- offline × 1
- option × 1
- orm × 1
- osx × 1
- owin × 1
- paper × 1
- parameter × 1
- performance × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- programming × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- ptvs × 1
- quant × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- real-time × 1
- reference × 1
- restful × 1
- round table × 1
- runtime × 1
- scriptcs × 1
- scripting × 1
- service × 1
- session-state × 1
- sitelet × 1
- sqlentityconnection × 1
- stickynotes × 1
- stress × 1
- strong name × 1
- structures × 1
- tdd × 1
- template × 1
- tracing × 1
- tsunamiide × 1
- type inference × 1
- type providers × 1
- typescript × 1
- upload × 1
- vb × 1
- vb.net × 1
- vector × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- visualstudio × 1
- web api × 1
- webapi × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- xml × 1
- zarovizsga × 1
|
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us |
Built with WebSharper |
I would spliit this list in list where new list start with number 1
and rename my sublist (I have no exact idea how to rename, but with this small exemple I can rename
and original list is now:
this example is "manual" => possible write a small F# code ? hints? suggestion?