Explanation for group by 3 elements from a list function using FOLD in OCAML

你说的曾经没有我的故事 提交于 2019-12-13 08:24:11

问题


I have a piece of code that does the following: group 3 elements of a list of n elements. The main function is called group_by_3. For example, executing group_by_3 [1;2;3;4;5;6;7] will give me ([1;2;3],[4;5;6],[7]).

let group_by_3 lst =
  let accum = ( [], [], 0 )
  in
  let f (all_groups, current_group, size) x =
    if size = 3
    then ( (List.rev current_group) :: all_groups, 
           [x], 1 )
    else ( all_groups, x::current_group, size+1)
  in
  let (groups, last, _) = List.fold_left f accum lst
  in List.rev ( List.rev last :: groups)

I don't really understand why this works (it is provided in class).

  • What are all_groups, current_group, size?
  • What does this do?

    if size = 3
    then ( (List.rev current_group) :: all_groups, 
           [x], 1 )
    else ( all_groups, x::current_group, size+1)
    

Thank you!


回答1:


All groups is the final answer, current is the group of three elements filled while parsing the input and size is the number of elements actually in current I guess.

Do you know the behavior of fold_left?




回答2:


What are all_groups, current_group, size?

These are the three pieces of state required to produce the groupings by visiting each item in the input sequence. These individual states are combined in a 3-tuple to form a single state for the fold. Ultimately we'll only care about all_groups, and the other two are just intermediate state necessary to construct that.

  • all_groups: This is a list value that accretes completed groupings. Whenever we've seen enough new elements to satisfy the group size, we make a new group and add it to this list.
  • current_group: This is also a list value, but more of a temporary buffer to build up a grouping until it reaches size. When it's big enough, it gets added to all_groups and is reset to a new group/list with the current item [x].
  • size this is just a counter to track how many items are in current_group.

What does this do?

if size = 3 simply decides whether we want to keep accumulating elements or if we've got enough for a grouping.

then ( (List.rev current_group) :: all_groups, [x], 1 ) is building/returning the new accumulator value, which is a 3-tuple of all_groups, current_group, and size. The List.rev call is necessary because of the way the list is being grown, in the else branch; it's fastest to add items to the front of a list, but this is the reverse of the input sequence thus we reverse them. x is the current item, which will be the first item in the new, growing group. 1 is of course the size of that new group.

else ( all_groups, x::current_group, size+1) is popping the current item x onto the front of the current_group list and incrementing the size counter.

Below that section is the logic that takes care of any straggler items that don't fit neatly into groupings of three.



来源:https://stackoverflow.com/questions/48713886/explanation-for-group-by-3-elements-from-a-list-function-using-fold-in-ocaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!