przemyxe0p
What do you do if you can not comprehend solution?
What do you do if you’ve done an exercise, it works, it’s not very inefficient and seems concise, then you go to the community solutions, sort by highest-rated user and see this?
defmodule Sublist do
@doc """
Returns whether the first list is a sublist or a superlist of the second list
and if not whether it is equal or unequal to the second list.
"""
def compare(a, b) when is_list(a) and is_list(b) do
case {contains?(a, b), contains?(b,a)} do
{true, true} -> :equal
{true, false} -> :superlist
{false, true} -> :sublist
{false, false} -> :unequal
end
end
# determines if list a contains list b. restore_a is needed to restore
# already "eaten" members of a, when b couldn't be matched completely
defp contains?(a, b, current_b \\ :initial, restore_a \\ nil)
defp contains?(a, b, :initial, nil), do: contains?(a, b, b, nil)
defp contains?(_, _, [], _), do: true
defp contains?([], _, _, _), do: false
defp contains?([x | a], b, [x | c], nil), do: contains?(a, b, c, a)
defp contains?([x | a], b, [x | c], restore_a), do: contains?(a, b, c, restore_a)
defp contains?([_ | a], b, _, nil), do: contains?(a, b, b, nil)
defp contains?(_, b, _, restore_a), do: contains?(restore_a, b, b, nil)
end
To clarify I enjoy creating solutions, and having to think, and play, but there is border.
Marked As Solved
mudasobwa
Create your own wrapper my_contains?/4 which would print the intermediate results and run it for several different inputs.
def compare(a, b) when is_list(a) and is_list(b) do
case {my_contains?(a, b), my_contains?(b,a)} do
{true, true} -> :equal
{true, false} -> :superlist
{false, true} -> :sublist
{false, false} -> :unequal
end
end
defp my_contains?(a, b, current_b \\ :initial, restore_a \\ nil) do
IO.inspect(a: a, b: b, current_b: current_b, restore_a: restore_a)
contains?(a, b, current_b, restore_a)
end
defp contains?(a, b, current_b \\ :initial, restore_a \\ nil)
defp contains?(a, b, :initial, nil), do: my_contains?(a, b, b, nil)
defp contains?(_, _, [], _), do: true
defp contains?([], _, _, _), do: false
defp contains?([x | a], b, [x | c], nil), do: my_contains?(a, b, c, a)
defp contains?([x | a], b, [x | c], restore_a), do: my_contains?(a, b, c, restore_a)
defp contains?([_ | a], b, _, nil), do: my_contains?(a, b, b, nil)
defp contains?(_, b, _, restore_a), do: my_contains?(restore_a, b, b, nil)```
Also Liked
derek-zhou
The code you cited seems fine to me, pretty clever use of tail recursion. I am not sure what do you mean. do you mean:
- You don’t like this code. Of course you can have a opinion and choose to use your own code. or:
- You like this code but wish some one to explain to you in digestible pieces. Then you did not say which part you do not understand. Or:
- You don’t care about this code at all, all you care is to win the competition to provide the best solution. Then it is a matter of skill issue, right?
derek-zhou
The correct reading order is from the top to bottom. If you want to improve your skill on tail recursion, write with it. Can you implement the enumerating functions in Enum, starting with Enum.reverse/1, with tail recursion? If you can write comfortably in tail recursion, it will click for you.
przemyxe0p
@spec flatten(list) :: list
def flatten(list), do: fl(list) |> Enum.reverse()
defp fl(list, acc \\ [])
defp fl([], acc), do: acc
defp fl([[_|_] = el | tail], acc), do: fl(el, acc) |> then(&fl(tail, &1))
defp fl([nil | tail], acc), do: fl(tail, acc)
defp fl([el | tail], acc),do: fl(tail, [el | acc])
I guess we should reverse at the end, not on intermediate states, and your suggestion would not work (I tested it).
How to tell if my above solution is proper tail-call recursion?







