#list #elixir
#Список #эликсир
Вопрос:
Я пытаюсь проанализировать флаги в стиле unix из args
списка, т.Е.:
args = ["hello", "-f", "val", "-u", "valtwo"]
# Desired outcome: [{"-f", "val"}, {"-u", "valtwo"}]
Мне удалось извлечь флаги с помощью следующего регулярного выражения:
args
|> Enum.filter(fn arg -> Regex.match?(~r/^-{1,2}w /, arg) end)
# ["-f", "-u"]
Однако, чтобы получить значения, соответствующие этим ключам, мне нужно получить значение аргументов в следующем индексе.
Я рассматривал возможность преобразования массива с использованием Enum.chunk_every(2)
(отбрасывая первый элемент, "hello"
), но это недостаточно гибко, поскольку это приведет к сбою в следующем:
["hello", "-f", "val", "secondvalforf", "-u", "valtwo"]
# Achieved outcome: [{"-f", "val"}, {"secondvalforf", "-u"}, {"valtwo"}]
Любые идеи приветствуются.
Ответ №1:
Enum.reduce/3
здесь твой друг.
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"]}]
Вызов Enum.reverse/1
результата для сохранения порядка ключей ( reduce
добавляет новые элементы в накопитель, чтобы избежать создания множества последующих связанных списков в будущем.)