Niek
Niek

Reputation: 1598

Enum Filtering: include value at index + 1

I am trying to parse unix-style flags from an args list, i.e.:

args = ["hello", "-f", "val", "-u", "valtwo"]
# Desired outcome: [{"-f", "val"}, {"-u", "valtwo"}]

I've managed to extract the flags with the following regex:

args
|> Enum.filter(fn arg -> Regex.match?(~r/^-{1,2}\w+/, arg) end)
# ["-f", "-u"]

However, in order to get the values that correspond to these keys, I need to get the value of args at the next index.

I've considered transforming the array using Enum.chunk_every(2) (discarding the first element, "hello"), but that's not sufficiently flexible, since that will break on the following:

["hello", "-f", "val", "secondvalforf", "-u", "valtwo"]
# Achieved outcome: [{"-f", "val"}, {"secondvalforf", "-u"}, {"valtwo"}]

Any ideas are greatly appreciated.

Upvotes: 0

Views: 89

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Enum.reduce/3 is your friend here.

args = ~w|hello -f val foo -u valtwo|
#⇒ ["hello", "-f", "val", "foo", "-u", "valtwo"]

Enum.reduce(args, [], fn 
  <<?-, _>> = key, args -> [{key, []} | args]
  _, [] -> [] # skip plain arguments
  arg, [{key, last} | rest] -> [{key, last ++ [arg]} | rest]
end)
#⇒ [{"-u", ["valtwo"]}, {"-f", ["val", "foo"]}]

Call Enum.reverse/1 on the result to preserve the order of keys (reduce prepends new elements to the accumulator to avoid creating many subsequent linked lists down the road.)

Upvotes: 2

Related Questions