1

I have a binary as follows: <<123, 249, 222, 67, 253, 128, 131, 231, 101>>

And I'd like to transform it into a list of structs like this:

[%RGB{red: 123, green: 249, blue: 222}, %RGB{red: 67, green: 253, blue: 128}, %RGB{red: 131, green: 231, blue: 101}].

The RGB struct is defined like this:

defmodule RGB do
  defstruct red: 0, green: 0, blue: 0
end

I have tried the following method:

  def to_rgb(data) when is_binary(data) do
    stage = 0 # R:0, G:1, B:2, 3:Complete
    rgb = %RGB{}
    rgblist = []
    for x <- :binary.bin_to_list(data) do
      cond do
        stage == 0 -> rgb = %{rgb | red: x}
        stage == 1 -> rgb = %{rgb | blue: x}
        stage == 2 -> rgb = %{rgb | green: x}
      end
      if stage == 3 do
        rgblist = rgblist ++ [rgb]
        stage = 0
      end
    end
    rgblist
  end

But it is far from elegant and doesn't work (the return value is an empty list).

1
  • 1
    "doesn't work (the return value is an empty list)" The reason why it doesn't work is because unlike imperative languages, (re)assigning a variable within if/cond/for has no effect, these blocks are expressions, not statements, and will just return a value. Variable scoping is briefly explained here. Commented May 1, 2022 at 16:04

1 Answer 1

3

You can parse the r, g, b values out of the binary 3 at a time using bitstring generators, and place them into the struct:

def to_rgb(data) when is_binary(data) and rem(byte_size(data), 3) == 0 do
  for <<r, g, b <- data>> do
    %RGB{red: r, green: g, blue: b}
  end
end

Output:

[
  %RGB{blue: 222, green: 249, red: 123},
  %RGB{blue: 128, green: 253, red: 67},
  %RGB{blue: 101, green: 231, red: 131}
]
Sign up to request clarification or add additional context in comments.

2 Comments

Isn't the rem(byte_size(data), 3) == 0 function guard technically unnecessary since it will MatchError anyway? Anyway, thank you for the solution.
Without the byte_size guard, any remainder bytes will be ignored. With the guard, you'll get a FunctionClauseError saying it doesn't match the guard.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.