Reputation: 35
I want to create a rec function, say oddleninLdbl
, that takes as an argument a list of lists "L" and returns a copy of "L" in which the lists of odd length have been "doubled" - doubled here means the list will concatenate with itself.
To illustrate the above, the idea is to have this :
oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];;
returns the following:
[[]; [5;5]; [23;5]; [45;65;2;45;65;2]; []; [34;85;7;22;1;34;85;7;22;1]]
it should also work with whatever list type, again for example this here with strings:
oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]]
should return:
[[]; ["mi";"lo"]; ["la";"la"]; ["lo";"co";"mo";"lo";"co";"mo"]]
I've been running in circles around this one. If I'm not mistaken, I know that my 'if expression' should revolve around something related to the length of the lists within a list, and when it is List.length mod 2 = 1
the sub-list should concatenate with itself.
But, I'm unable to apply it as I've never worked with list of lists! How should this function be written? Your help is much appreciated.
EDIT 1:
I've tried to do the following
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
but I'm getting this as an answer :
# oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]] ;;
- : int list list =
[[5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]; [5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]]
# oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]] ;;
- : string list list =
[["mi"; "lo"]; ["la"]; ["lo"; "co"; "mo"]; ["mi"; "lo"]; ["la"];["lo"; "co"; "mo"]]
# oddleninLdbl [5;6;3;4;6] ;;
- : int list = [5; 6; 3; 4; 6; 5; 6; 3; 4; 6]
# oddleninLdbl [4;5] ;;
- : int list = [5; 5]
# oddleninLdbl [4;5;8] ;;
- : int list = [4; 5; 8; 4; 5; 8]
# oddleninLdbl [4;5;8;9] ;;
- : int list = [5; 8; 9; 5; 8; 9]
# oddleninLdbl ["mi";"lo"] ;;
- : string list = ["lo"; "lo"]
# oddleninLdbl ["mi";"lo";"co"] ;;
- : string list = ["mi"; "lo"; "co"; "mi"; "lo"; "co"]
# oddleninLdbl ["mi"] ;;
- : string list = ["mi"; "mi"]
Clearly not what is expected of this function to do. Where is the culprit in my code? Could someone give me their diagnosis?
EDIT 2 :
let double_list l = (List.hd l)@(List.hd l);;
let p l = (List.length (List.hd l)) mod 2 = 1 ;;
let apply p double_list l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then double_list hd else hd in
aux (hd :: acc) tl ;;
I am getting syntax error on this one surely I've skipped something here. What do you think?
Upvotes: 0
Views: 245
Reputation: 4441
A good rule of thumb when working with structures that you can't easily understand is to divide and conquer.
Your problem, here, can be decomposed in multiple parts:
So, you should first create a simple function that doubles a list
let double_list l = (* double the elements in a list of elements *)
Then you should create a function that traverses a list of elements and does something when the current element correspond to a predicate p
let apply p f l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then f hd else hd in
aux (hd :: acc) tl
in aux [] l
Now the only thing you need is the proper predicate p
and you already implemented your function f
and it should work perfectly.
To summarize, never be afraid of an apparent complexity when you can just simplify your problem by dividing it in smaller problems.
EDIT:
Here is your code:
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
This is not idiomatic OCaml, try to use pattern-matching instead:
let double_list l = l@l;;
let rec oddleninLdbl l =
match l with
| [] -> []
| hd :: tl ->
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl tl;;
As you can see, you're checking if l
is odd, not its element, which is not what you want to do. You want to check if hd
is odd and double it then keep traversing the rest of the list and append hd
(doubled or not) to the result of the recursive call. Here, when l
is odd you double it and stop and if it's not you just forget the head of the list and double the rest (since the rest will logically be an odd list).
Upvotes: 1