stackcats
The problem needs to keep track of the encoding list
So I used GenServer to solve this
This is the first version of the code
defmodule RLEIterator do
use GenServer
@spec init_(encoding :: [integer]) :: any
def init_(encoding) do
GenServer.start_link(__MODULE__, encoding, name: __MODULE__)
end
@spec next(n :: integer) :: integer
def next(n) do
GenServer.call(__MODULE__, {:next, n})
end
def init(encoding) do
{:ok, encoding}
end
def handle_call({:next, n}, _from, state) do
{res, new_state} = next_(n, state)
{:reply, res, new_state}
end
defp next_(_n, []), do: {-1, []}
defp next_(n, [ct, num | rest]) do
if ct >= n do
{num, [ct - n, num | rest]}
else
next_(n - ct, rest)
end
end
end
The code will be called as such:
RLEIterator.init_([3, 8, 2, 5])
param_1 = RLEIterator.next(2)
RLEIterator.init_([2, 5, 3, 8])
param_1 = RLEIterator.next(5)
I got the wrong answer.
Because there are multiple test cases with one GenServer instance.
So I changed my code
defmodule RLEIterator do
use GenServer
@spec init_(encoding :: [integer]) :: any
def init_(encoding) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
GenServer.call(__MODULE__, {:init, encoding})
end
@spec next(n :: integer) :: integer
def next(n) do
GenServer.call(__MODULE__, {:next, n})
end
def init(encoding) do
{:ok, encoding}
end
def handle_call({:init, encoding}, _from, _state) do
{:reply, [], encoding}
end
def handle_call({:next, n}, _from, state) do
{res, new_state} = next_(n, state)
{:reply, res, new_state}
end
defp next_(_n, []), do: {-1, []}
defp next_(n, [ct, num | rest]) do
if ct >= n do
{num, [ct - n, num | rest]}
else
next_(n - ct, rest)
end
end
end
I think it’s so ugly in function init_.
How to improve the code?
Trending in Questions
Hey guys,
I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly
Do you guys have any suggestions what is the best prac...
New
Hello!
Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app.
I creat...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
I’m trying to set up Emacs with elixir-ls via lsp-mode and credo via Flycheck. This should mostly be preconfigured as Flycheck picks up c...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
Sebb
You don’t need a GenServer for RLE. Thats just a function.
Seems like you want to do OO in Elixir.
It could look sth like
stackcats
How to do OO in Elixir such as Class static fields without GenServer or Agent?
Sebb
I think there is a good thread here about transition from OO to Elixir, but I can’t find it.
The very short answer is: create a module with a
defstructwhich replaces the attributes. The functions of the module replace the methods. The functions get an instance of the struct as argument. Inheritance is replaced by aggregation.stackcats
But the signature of the function can’t be changed in leetcode.
mudasobwa
This line in subsequent calls to
init_/1won’t do what you think it will. There might be only one instance with the nameRLEIteratorrunning, meaning the second and all other calls would return{:error, {:already_started, pid}}tuple andnext/1will send a message to the very first instance started. That is one of the reasons you are better to directly pattern match on the return value ofGenServer.start_link/3.You likely need an agent, keeping the map
%{encoding ⇒ pid}and a bunch of anonymous instances ofRLEIterators.stackcats
How to find the corresponding
GenServerwhen callingRLEIterator.next(2)?Agentneeds theencodinglist to getpidmudasobwa
Ah, indeed.
next/1, accepting an integer only, won’t likely work in the concurrent environment at all.Then what has been suggested above (no processes, no state, plain old good recursion) is the way to go.
deadbeef
TL;DR: I think @stackcats solution is basically spot on. Just dealing with LeetCode’s contrived problem setup/environment is awkward and basically forces anti-patterns.
Here’s my solution: https://leetcode.com/problems/rle-iterator/solutions/5024907/elixir-solved-with-recursion-state-held-in-agent/
Sorry to necropost, but came across this post while I’ve been doing LeetCode problems.
@Sebb is correct that this problem can be solved without
GenServeror any “state” management. However, also pointed out, LeetCode setup the “API” in a way that we can’t just recurse/yield results. So we do need a way of storing state for subsequent calls tonext/1.IMO, it’s a bit contrived for Elixir, but I assume LeetCode has adapted this in “spirit” of other languages implementations.
I believe the problem can be “generically” (i.e. without
GenServer) with something like this:We find the value, then return the updated list, which will be used for subsequent calls.
@mudasobwa is correct about how subsequent calls to
init_/1(in current impl.) will result in{:error, {:already_started, pid}}, and that normally you’d use something like a dynamic supervisor, something to manage anonymous processes, or something. I feel test cases would normally manage resetting processes or have one “fresh” one per test case (or something). However, LeetCode provides a black box and just tells usSo, to me, this also feels a bit contrived, but need to adapt to the LeetCode environment. So we need a way to setup the process on the first call, then “reset” on every subsequent call.
To handle the multi-calls to
init_/1, I’m sure we could do something with superviors/anonymous processes or something. Instead, I kept the process “well-known” (i.e.name: __MODULE__) and “reset” it on subsequent calls withAgent.cast/2, i.e.It’s kinda hacky, IMO, but feels fine/fitting for the blackbox environment the problem suggests/provides.
I found this problem to be similar to 380. Insert Delete GetRandom O(1), which also heavily suggests the use of
GenServeror the like.Now that we have our “generic” solution and handled
init_/1, we just need to wrapdo_next/2by havingnext/1leverageAgent. I used it like this:do_next/2’s return is already in the form of{a, state()}, so we can just calldo_next/2and pass in the current state andn.My full solution here: https://leetcode.com/problems/rle-iterator/solutions/5024907/elixir-solved-with-recursion-state-held-in-agent/
deadbeef
Solution copy/pasted (in case someone doesn’t want/can’t click the link):
christhekeele
Yep, this “reducer” pattern is pretty idiomatic Elixir, especially as you formulated it: a
def xxx/1that calls a recursivedefp do_xxx/2with an empty list as an initial accumulator, that returns the accumulator from the result of the final recursion. You’ll often see theacclast, rather than first, in your example.This is also a reasonable use-case for the (often discouraged in production use) process dictionary (see:
Process.put/2,Process.get/1,Process.delete/1).