У меня есть список как это:
[["str1","str2"],["str3","str4"],["str5","str6"]]
И я должен преобразовать его в
["str1", "str2", "str3", "str4", "str5", "str6"]
Как я делаю это?
Проблема состоит в том, что я имею дело со списками строк, поэтому когда я делаю
lists:flatten([["str1","str2"],["str3","str4"],["str5","str6"]])
Я добираюсь
"str1str2str3str4str5str6"
Однако, если элементы исходного списка, где просто атомы, затем lists:flatten
дал бы мне, в чем я нуждался. Как я достигаю того же со строками?
списки: append делает именно то, что вам нужно:
1> lists:append([["str1","str2"],["str3","str4"],["str5","str6"]]).
["str1","str2","str3","str4","str5","str6"]
(списки: concat работает правильно, но тоже угрожает выполнить некое преобразование типов.)
Если ваш список всегда является "списком списков строк", то вы можете просто использовать оператор foldl
, используя что-то вроде:
Flat = list:foldl(fun(X, Acc) -> X ++ Acc end, [], List)
В случае, когда вложенность вашего списка может быть произвольной глубины, я бы предложил сообщить erlang, что ваши строки не являются простыми списками символов, используя кодировку, такую как:
[[{string, "str1"},{string, "str2"}],
[{string, "str3"}, {string, "str4"}],
[{string, "str5"},{string, "str6"}]]
Таким образом, list:flatten
сделает все правильно и выдаст:
[{string, "str1"},{string, "str2"},
{string, "str3"}, {string, "str4"},
{string, "str5"},{string, "str6"}]
который вы сможете при необходимости преобразовать обратно в необработанный список строк с помощью foldl
.
Если ваши строки должны обрабатываться иначе, чем просто списки символов, то они, вероятно, заслуживают того, чтобы быть настоящей структурой данных, см. эту запись в блоге для интересного обсуждения этого вопроса.
Причина, по которой lists:flatten не работает, заключается в том, что строки в Erlang - это просто списки маленьких целых чисел. Мы можем решить эту проблему с помощью функции, которая прекращает рекурсию вниз во вложенном списке, если список является просто строкой.
Для произвольно вложенного списка строк можно использовать следующую функцию:
slab([]) ->
[];
slab([F|R]) ->
case io_lib:char_list(F) of
true -> [F|slab(R)];
false -> slab(F) ++ slab(R)
end.
Она использует io_lib:char_list(), чтобы решить, была ли рекурсия вложенности достаточно глубокой.
Пример работы:
1> slab([[["foo", "bar"], "baz", [[[["foobar"]]]], "froboz", "the end"]]).
["foo","bar","baz","foobar","froboz","the end"]
2>
Небольшое улучшение, которое позволило бы использовать смешанные вложенные списки:
slab([]) ->
[];
slab([F|R]) when is_list(F) ->
case io_lib:char_list(F) of
true -> [F|slab(R)];
false -> slab(F) ++ slab(R)
end;
slab([F|R]) ->
[F|slab(R)].
Эта функция ведет себя так же, как lists:flatten, за исключением того, что она обрабатывает строки так, как если бы они не были списками:
1> slab([[["foo", "bar"], "baz", [[[["foobar", atom]],[a,b,c]]], 2, "froboz", "the end"]]).
["foo","bar","baz","foobar",atom,a,b,c,2,"froboz","the end"]