Эликсир найти самую длинную подстроку в строке - PullRequest
0 голосов
/ 06 мая 2020

Мой вопрос точно такой же, как Найти самую длинную подстроку в строке

Но связано с эликсиром

Моя текущая реализация очень уродливая:

str = "aabbbssssssggssrrrr"
String.split(str, "") |> Enum.chunk_while([], fn elem, acc ->
  cond do
    (length(acc) == 0) -> 
    {:cont, [elem]}
    (acc == [""]) -> 
      {:cont, [elem]}
    (List.last(acc) == elem) -> 
      {:cont, [elem | acc]}
    true -> 
    {:cont, Enum.reverse(acc), []}
  end
end,
fn
  [] -> {:cont, []}
  acc -> {:cont, Enum.reverse(acc), []}
end) |> Enum.map(fn e -> Enum.reduce(e, "", &<>/2) end) |> Enum.max_by(&String.length/1)

Можно ли написать однострочник как в ruby или хоть что-то короче?

Ответы [ 2 ]

3 голосов
/ 06 мая 2020

Наиболее подходящим решением для elixiri sh было бы использование Enum.reduce/3, что делает это O(N) за один проход ввода.

"aabbbssssssggssrrrr"
|> to_charlist()
|> Enum.reduce(%{char: ??, curr: 0, max: []}, fn
  ch, %{char: ch, max: max, curr: curr} when curr < length(max) -> 
    %{char: ch, max: max, curr: curr + 1}

  ch, %{char: ch, curr: curr} -> 
    %{char: ch, max: List.duplicate([ch], curr + 1), curr: curr + 1}

  ch, %{max: max} ->
    %{char: ch, max: max, curr: 1}
end)
|> Map.get(:max)
|> Enum.join()
#⇒ "ssssss"
1 голос
/ 06 мая 2020

Связанное решение с фрагментами чрезвычайно бедно. Он выполняет несколько абсолютно ненужных операций, таких как разделение, соединение et c, что может резко снизить производительность на длинных входах.

Самый простой способ - использовать регулярное выражение с обратной ссылкой .

str = "aabbbssssssggssrrrr"
Regex.scan(~r/(.)\1{1,}/, str, capture: :first)
#⇒ [["aa"], ["bbb"], ["ssssss"], ["gg"], ["ss"], ["rrrr"]]

Теперь это вопрос предпочтений, как добраться до самой длинной строки, например:

~r/(.)\1{1,}/
|> Regex.scan(str, capture: :first)
|> Enum.sort_by(&-String.length(hd(&1)))
|> hd()
|> hd()
#⇒ "ssssss"

или List.flatten/1

~r/(.)\1{1,}/
|> Regex.scan(str, capture: :first)
|> List.flatten()
|> Enum.sort_by(&-String.length(&1))
|> hd()
#⇒ "ssssss"
...