39道题练习记录
% 练习题1 将列表中的integer,float,atom转成字符串并合并成一个字个字符串:[1,a,4.9,"sdfds"] 结果:"1a4.9sdfds"(禁用++ -- append concat实现)
-module(q1).
-export([getStr/1,to_string/1]).
% 若输入列表为空列表则输出“”
getStr([]) -> "";
% 构建函数 遍历列表,判断元素类型并转换为字符串放入列表
getStr([H|T]) ->
if
is_atom(H) -> [atom_to_list(H)|getStr(T)];
is_integer(H) ->[integer_to_list(H)|getStr(T)];
is_float(H) -> [float_to_list(H,[{decimals,1}])|getStr(T)];
is_list(H) -> [H | getStr(T)]
end.
% 构建函数 利用将列表转换为二进制数据,再将二进制数据转为列表的方式将列表中的字符串合并
to_string(List) ->
binary_to_list(list_to_binary(getStr(List))).
技术点 :
1. if表达式
2. 列表中的字符串合并转换为字符串 binary_to_list(list_to_binary(list)).
3. 关卡判断函数的掌握
4. erlang内建函数的掌握 特别注意float_to_list()中参数设置
% 练习题2 得到列表或元组中的指定位的元素 {a,g,c,e} 第1位a [a,g,c,e] 第1位a(禁用erlang lists API实现)
% 思路 : 该题涉及列表与元组,指定位置最后输出元素,那么传入参数可以有两个,传入的列表或者元组,以及想得到的位置参数,然后考虑传入列表及元组为空的情况;之后传入的参数可能为列表也可能为元组,两个数据类型不能用同一方式进行处理,所以首先做出判断是列表还是元素,分开进行处理,当传入参数是元组时,元组难以如列表一样方便遍历,那么就将元组转换为列表进行操作,操作列表时我们需要通过遍历每个元素,确认位置来匹配元素,发现缺失当前位置的参数,那么就设置一个当前位置参数index ->1,利用递归遍历一次index+1,再利用设置位置与当前位置匹配,匹配成功则输出元素,得解.
-module(q2).
% 设置两个参数 列表或元组 以及 想得到的位置
-export([get_index_val/2]).
%设置输入为空时的输出
get_index_val([],Position) -> [];
get_index_val({},Position) -> {};
get_index_val(List, Position) ->
% 判断传入的List是元组的情况 将元组转换为列表方便遍历
if
is_tuple(List) ->
get_index_val(tuple_to_list(List),Position,1);
true ->
get_index_val(List, Position, 1)
end.
% 设置一个当前位置参数index 遍历列表的同时用index来匹配Position 从而输出遍历到Position的元素 输出
get_index_val([H|T], Position, Index) when Position == Index ->H;
get_index_val([H|T], Position, Index) ->
get_index_val(T, Position, Index+1).
技术点 :
1. 关卡 : when
2. BIF : tuple_to_list
3. if表达式
4. 列表操作 + 递归 实现遍历的基本运用
% 练习三 根据偶数奇数过滤列表或元组中的元素(禁用API实现)
% 思路 : 要过滤列表或元组的奇偶数,需要遍历列表,如过为元组转化为列表进行遍历操作,遍历的每个元素进行奇偶判断,并进行分组分在两个列表
-module(q_3).
-export([my_filter/1]).
% 处理输入空列表空元组
my_filter([]) -> "[]";
my_filter({}) -> "{}";
% 判断元组和列表
my_filter(List) ->
if
is_tuple(List) -> my_filter(tuple_to_list(List));
true -> my_filter(List, [], [])
end.
% 遍历列表判断奇偶
my_filter([H|T], Odd, Even) ->
case (H rem 2) of
1 -> my_filter(T,[H| Odd], Even);
0 -> my_filter(T, Odd, [H | Even])
end;
%输出过滤后的值
my_filter([], Odd, Even) ->
{Odd, Even}.
技术点 :
1. BIF tuple_to_list
2. if 表达式
3. 列表操作 + 递归 实现遍历
4. case 表达式
% 练习4 便用匿名函数对列表奇数或偶数过淲
% 本题可以用lists API 省去了遍历的过程 直接利用lists:filter 用匿名函数设置过滤条件
-module(q_4).
-export([fun_filter/1]).
fun_filter(List) ->
Odd = fun(X) -> (X rem 2) == 0 end,
Even = fun(X) -> (X rem 2) == 1 end,
{lists:filter(Odd,List), lists:filter(Even, List)}.
技术点 :
1. 匿名函数fun
2. list API lists:filter()
% 练习5 计算数字列表[1,2,3,4,5,6,7,8,9]索引N到M的和
-module(q_5).
-export([sum_index/3]).
sum_index([], N, M) -> "0";
sum_index(List, N, M) ->
% 判断N和M的大小.小在前大在后
if
N > M -> sum_index(List, M, N);
true -> sum_index2(List, N, M, 1, 0)
end.
sum_index([H | T], N, M, Index, Sum) when N =< Index ->
sum_index3(T, N, M, Index+1, Sum+H).
sum_index2([H | T], N, M, Index, 0) ->
sum_index(T, N, M, Index+1, 0).
sum_index3([H | T], N, M, Index, Sum) ->
if
Index == M -> Sum + H;
true -> sum_index([H|T], N, M, Index, Sum)
end.
% 练习6 查询List1是为List2的前缀(禁用string API实现)
-module(q_6).
-export([is_prefix/2]).
is_prefix([], List2) -> false;
is_prefix([], []) -> false;
is_prefix(List1, List2) ->
if
length(List1) >= length(List2) -> false;
true -> is_prefix2(List1,List2)
end.
is_prefix2([H1|T1],[H2|T2]) ->
if
(H1 == H2 andalso T1 == [] ) -> true;
H1 == H2 -> is_prefix2(T1,T2);
H1 /= H2 -> false;
T1 == [] -> true
end.
% 练习7 逆转列表或元组(禁用lists API实现)
-module(q_7).
-export([my_reserve/1]).
my_reserve([]) -> [];
my_reserve(List) ->
if
is_tuple(List) -> my_reserve(tuple_to_list(List), [], List);
true -> my_reserve(List, [] , List)
end.
my_reserve([H|T], NewList, List) ->
my_reserve(T, [H|NewList],List);
my_reserve([], NewList, List) ->
if
is_tuple(List) ->list_to_tuple(NewList);
true -> NewList
end.
% 练习8 对列表进行排序
-module(q_8).
-export([quick_sort/1]).
quick_sort([]) ->[];
quick_sort([H|T]) ->
quick_sort([X || X <- T , X > H])
++ [H] ++
quick_sort([X || X <- T, X < H]).
% 练习9 对数字列表进行求和再除以指定的参数,得到商余
-module(q_9).
-export([get_sum_rem/2]).
get_sum_rem(List, Num) ->
get_sum_rem(List, Num, 0).
get_sum_rem([H|T], Num, Sum) ->
get_sum_rem(T, Num, Sum + H);
get_sum_rem([], Num, Sum) ->
{Sum div Num, Sum rem Num}.
% 练习10 获得当前的堆栈
try generate_exception(5)
catch
error:X->
{X,erlang:get_stacktrace()}
end.
% 练习11 获得列表或元组中的最大最小值(禁用API实现)
-module(q_11).
-export([get_max_min/1]).
get_max_min([H|T]) ->
get_max_min(T, H, H).
get_max_min([H1|T1], Max, Min) ->
if
Max =< H1 -> get_max_min(T1, H1, Min);
Min >= H1 -> get_max_min(T1, Max, H1);
true -> get_max_min(T1, Max, Min)
end;
get_max_min([], Max, Min) ->
{max, Max, min, Min}.
% 练习12 查找元素在元组或列表中的位置
-module(q_12).
-export([get_index/2]).
get_index(List, Element) ->
get_index(List, Element, 1).
get_index([H|T], Element, Index) ->
if
H == Element -> Index;
H /= Element -> get_index(T, Element, Index+1);
T == [] -> null
end.
% 练习14判断A列表([3,5,7,3])是否在B列表([8,3,5,3,5,7,3,9,3,5,6,3])中出现,出现则输出在B列表第几位开始
-module(q_13).
-export([is_in_index/2]).
is_in_index(ListA, ListB) ->
if
length(ListA) > length(ListB) -> false;
true -> is_in_index(ListA, ListB, 1, 1)
end.
is_in_index([Ha|Ta], [Hb|Tb], IndexA, IndexB) ->
if
Ha == Hb -> is_in_index(Ta, Tb, IndexA, IndexB+1);
(Ha /= Hb) and (IndexB /= 1) -> false;
Ha /= Hb -> is_in_index([Ha|Ta], Tb, IndexA + 1, IndexB)
end;
is_in_index([], List, IndexA, IndexB) ->{true, index, IndexA}.
% 练习15 {8,5,2,9,6,4,3,7,1} 将此元组中的奇数进行求和后除3的商(得值A),并将偶数求和后乘3(得值B),然后求A+B结果
-module(q_14).
-export([ab_add/1]).
ab_add(List) ->
ab_add(tuple_to_list(List), 0, 0).
ab_add([H | T], A, B) ->
case (H rem 2) of
1 -> ab_add(T, A + H, B);
0 -> ab_add(T, A, B + H)
end;
ab_add([], A, B) ->
{result, (A div 3) + (B *3) }.
% 练习16 在shell中将unicode码显示为中文
io:format(“test===pn”,[“测试”]).
io:format(“test====tsn”,[“测试”]).
unicode:characters_to_list(list_to_binary([230,181,139,232,175,149]))
.
io:format(“test===tsn”,[[27979,35797]]).
% 练习17 传入列表L1=[K|_]、L2=[V|_]、L3=[{K,V}|_],L1和L2一一对应,L1为键列表,L2为值列表,L3存在重复键,把L3对应键的值加到L2
-module(q_17).
-export([key_val/3]).
key_val(L1, L2, L3)->
key_val(L1, L2, L3, [], L1).
key_val([H1 | T1], [H2 | T2], [{K, V} | T3], NewL2, L1) ->
if
K == H1 -> key_val(T1, T2, [{K, V} | T3], lists:append([H2+V] , NewL2), L1);
K /= H1 -> key_val(T1, T2, [{K, V} | T3], lists:append([H2] , NewL2), L1)
end;
key_val([], [], [{K,V} | T3], NewL2, L1) ->
key_val(L1, NewL2, T3, [], L1);
key_val(L1, NewL2, [], [], L1) -> NewL2.
% 练习18 删除或查询元组中第N个位置的值等于Key的tuple(禁用lists API实现)
-module(q_18).
-export([drop_select/3]).
drop_select(Tuple, N, Key) ->
drop_select(tuple_to_list(Tuple), N, Key, 1, Tuple).
drop_select([{K , V}|T], N, Key, Index, Tuple) when (N == Index) andalso (Key == V) ->
erlang:delete_element(Index, Tuple);
drop_select([{K , V}|T] , N, Key, Index, Tuple) ->
drop_select(T, N, Key, Index+1, Tuple).
% 练习19 对一个字符串按指定符字劈分(禁用string API实现)
-module(q_19).
-export([string_div/2]).
string_div(Str, [X]) ->
string_div(Str, X, [], []).
string_div([H | T], X, Res, L) ->
if
H /= X -> string_div(T, X, Res, lists:append(L, [H]));
H == X -> string_div(T, X, lists:append(Res, [L]), [])
end;
string_div([], X, Res, L) -> lists:append(Res, [L]).
%练习20 合并多个列表或元组
-export([mergeList/1,mergeTuple/1]).
mergeList(List)->mergeList2(List).
mergeList2([H|R])->H ++ mergeList?;
mergeList2([])->[].
mergeTuple2(Tuple1List)->mergeTuple3(Tuple1List).
mergeTuple3([H|R])-> tuple_to_list(H) ++ mergeTuple2?;
mergeTuple3([])->[].
mergeTuple(Tuple1List)->
X=mergeTuple2(Tuple1List),
Y=list_to_tuple(X)
% 练习22 排序[{"a",5},{"b",1},{"c",8},{"d",7},{"e",3},{"f",9},{"g",2},{"h",6},{"i",4}], 以元组的值进行降序 优先用API
-module(q_22).
-export([get_sort/1]).
get_sort(List) ->
lists:reverse(lists:keysort(2, List)).
% 练习23 {8,5,2,9,6,4,3,7,1} 将此元组中的奇数进行求和
-module(q_23).
-export([odd_sum/1]).
odd_sum(Tuple) ->
odd_sum(tuple_to_list(Tuple), 0).
odd_sum([H | T], Sum) ->
case (H rem 2 ) of
0 -> odd_sum(T, Sum);
1 -> odd_sum(T, Sum+H)
end;
odd_sum([], Sum) -> Sum.
% 练习24
-module(q_24).
-export([do_tuple/4]).
do_tuple(I1, I2, D, Tuple) ->
do_tuple(I1, I2, D, tuple_to_list(Tuple), 1, 0, 0, tuple_to_list(Tuple)).
do_tuple(I1, I2, D, [H | T], Index, V1, V2, Lists) ->
if
I1 == Index -> do_tuple(I1, I2, D, T, Index+1, H, V2, Lists);
I2 == Index -> do_tuple2(I1, I2, D, T, Index+1, V1, H, Lists);
true -> do_tuple(I1, I2, D, T, Index+1, V1, V2, Lists)
end.
do_tuple2(I1,I2,D,List,Index,V1,V2,Lists) ->
case (V1 == V2) of
true -> do_tuple3(I2-1,D,0,lists:delete(V1,Lists), []);
false -> do_tuple_false(I2,V1,0,lists:delete(V2,Lists), [])
end.
do_tuple3(I2,D,Index,[H|T],NewList) when I2 == Index ->
do_tuple3(I2,D,Index+1,T,lists:append(NewList,[D]));
do_tuple3(I2,D,Index,[H|T],NewList) ->
do_tuple3(I2,D,Index+1,T, lists:append(NewList,[H]));
do_tuple3(I2,D,Index,[],NewList) -> list_to_tuple(NewList).
do_tuple_false(I2,V1,Index,[H|T], NewList) when I2 == Index ->
do_tuple_false(I2,V1,Index+1 , T, lists:append(NewList,[V1]));
do_tuple_false(I2,V1,Index,[H|T], NewList) ->
do_tuple_false(I2,V1,Index+1, T, lists:append(NewList,[H]));
do_tuple_false(I2, V1, Index, [], NewList) -> list_to_tuple(NewList).
% 练习25 删除列表或元组中全部符合指定键的元素
-module(q_25).
-export([drop_mb/2]).
drop_mb(List, Key) ->
drop_mb(List, Key, List).
drop_mb([{K,V} | T], Key, NewList) when K == Key -> drop_mb(T, Key, lists:keydelete(K, 1, NewList));
drop_mb([H|T], Key, NewList) ->
drop_mb(T,Key, NewList);
drop_mb([], Key, NewList) -> NewList.
% 练习26 替换列表或元组中第一个符合指定键的元素
-module(q_26).
-export([change_One/2]).
change_One(List, Kv) ->
change_One(List, Kv, List).
change_One([{K,V}|T], {K1,V1}, NewList) when K == K1 -> lists:keyreplace(K, 1, NewList, {K1,V1});
change_One([H|T], Kv, NewList) ->
change_One(T, Kv, NewList);
change_One([], Kv, NewList) -> NewList.\
% 练习27 将指定的元素插入到列表中指定的位置,列表中后面的元素依次向后挪动
-module(q_27).
-export([my_insert/3]).
my_insert(List, Val, Position)->
my_insert(List, Val, Position, 1, []).
my_insert(List, Val, Position, Index, NewList) when Position == Index ->
NewList ++ [Val] ++ List ;
my_insert([H|T], Val, Position, Index, NewList) ->
my_insert(T, Val, Position, Index+1, lists:append(NewList,[H]));
my_insert([], Val, Position, Index, NewList) -> NewList.
% 练习28 对[6,4,5,7,1,8,2,3,9]进行排序(降序--冒泡排序)或API排序
-module(q_28).
-export([pop_sort/1]).
pop_sort(List) ->
pop_sort([], List).
pop_sort(NewList,[]) ->
NewList;
%循环直到原列表为空列表
pop_sort(NewList, List) ->
pop_sort(NewList ++ [lists:max(List)], lists:delete(lists:max(List), List)).
%找出列表最大值加入空列表
%删除原列表最大值
% 练习29 将字符串"goods,143:6|money:15|rmb:100|money:100|goods,142:5"解析成[{money,115},{rmb,100},{goods,[{143,6},{142,5}]}]可以代码写定KEY进行匹配归类处理
-module(q_29).
-export([dostr/1,is_in/1,do_goods/1,do_others/1,mul/1,star/0]).
star() ->
List = dostr("goods,143:6|money:15|rmb:100|money:100|goods,142:5"),
mul(List).
% 设置函数整合元组列表
mul(List) ->
mul(List, []).
mul([], NewList) -> NewList;
mul([{K,V}| T], NewList) ->
case lists:keymember(K,1,NewList) of
true -> mul(T, NewList);
false -> mul(T, NewList ++ [res([{K,V}|T], K)])
end.
res([{K, V}|T], X) ->
if
is_tuple(V) ->
{K, proplists:append_values(K, [{K,V}|T]) };
true ->
{K, lists:sum(proplists:append_values(K, [{K,V}|T]))}
end.
%设置一个判断元素是否在字符串里的函数is_in()
is_in([]) -> false;
is_in([H|T]) ->
if
H == $, -> true;
H /= $, -> is_in(T)
end.
%构建处理goods的函数
do_goods(List) ->
do_goods(List, 1).
do_goods([H|T] , Index) ->
if
Index == 1 -> [list_to_atom(H)|do_goods(T, Index+1)];
true -> [{list_to_integer(H),list_to_integer(lists:last(T))}]
end.
%构建处理其他键值的函数
do_others([H,T]) -> {list_to_atom(H),list_to_integer(T)} .
% 先将字符串以 | 分割, 遍历->元组方式存入列表 string:to_integer
dostr(Str) ->
List = string:tokens(Str, "|"),
dostr2(List).
dostr2([]) ->[];
dostr2([H|T]) ->
case is_in(H) of
true ->
[list_to_tuple(do_goods(string:tokens(H, ",:"))) | dostr2(T)];
false ->
[do_others(string:tokens(H, ":")) | dostr2(T)]
end.
% 练习30 移除元组或列表中指定位置的元素
-module(q_30).
-export([drop_index/2]).
drop_index(List, Position) ->
drop_index(List, Position, 1, []).
drop_index([H|T], Position, Index, NewList) when Position == Index ->
drop_index(T, Position, Index + 1, NewList);
drop_index([H|T], Position, Index, NewList) ->
drop_index(T, Position, Index+1, NewList ++ [H]);
drop_index([], Position, Index, NewList) -> NewList.
% 练习31 指定列表第几位之后的数据进行反转。如:指定[2,3,5,6,7,2]第3位后进行反转(谢绝一切API(lists:concat,lists:reverse等)、++、--方法)
-module(q_31).
-export([do_reverse/2,reverse_list/1]).
reverse_list(List)->
reverse_list(List, []).
reverse_list([H|T], Reverse_list)->
reverse_list(T, [H| Reverse_list]);
reverse_list([], Reverse_list) -> Reverse_list.
do_reverse(List, Position) ->
do_reverse(List, Position, 1).
do_reverse([H|T], Position, Index) when Position == Index ->
[H|reverse_list(T)];
do_reverse([H|T], Position, Index) ->
[H| do_reverse(T, Position, Index+1)].
% 练习32 使用“匿名函数”检查列表的每个元素是否符合传入的最大最小值(都是闭区间)
-module(q_32).
-export([is_max_min/3]).
is_max_min([H | T], Max, Min)->
Fun = fun(X, Max, Min) ->
case (X >= Max) or (X =< Min) of
true -> false;
false -> true
end
end,
case Fun(H, Max, Min) of
false -> false;
true -> is_max_min(T, Max, Min)
end;
is_max_min([], Max, Min) -> true.
注: or and 两边要加括号
% 练习34 成生指定数量元组,每个元素为随机integer元素, 元素不能有相同的
-module(q_34).
-export([random_int/1, drop_re/1]).
% 删除重复值的函数
drop_re(List) ->
drop_re(List, []).
drop_re([H|T], NewList) ->
case lists:member(H,NewList) of
true ->drop_re(T, NewList);
false -> drop_re(T, NewList ++ [H])
end;
drop_re([], NewList) -> NewList.
%生成指定数量的随机数
random_int(Num) ->
random_int(Num, 1, []).
random_int(Num, Index, NewList) when Num == Index ->
List2 = drop_re(NewList),
if
length(List2) /= Num -> random_int(Num, length(List2),List2);
true -> List2
end;
random_int(Num, Index, NewList) ->
random_int(Num, Index+1, NewList ++ [random:uniform(100)]).
%练习36 输入A(元子列表),B(数值列表)两个相同长度的参数进行随机匹配(要求字母为Key,数值为Value),支持指定的Key和Value在一组
-module(q_36).
-export([listMatch/2,randomNumber/1]).
randomNumber(Length)->
random:uniform(Length).
listMatch(List1,List2)->
listMatch(List1,List2,1).
listMatch(List1,List2,Index) when Index =< length(List1)->
Position1=randomNumber(length(List1)),
Position2=randomNumber(length(List2)),
[{lists:nth(Position1,List1),lists:nth(Position2,List2)}|listMatch(List1,List2,Index+1)];
listMatch(List1,List2,Index)->[].
% 练习37 对相同类型的数据进行拼接
-module(q_37).
-export([my_join/1]).
my_join(L)->
my_join(L, [], [], []).
my_join([H|T], Binary, Tuple, List)->
if
is_binary(H) -> my_join(T,Binary ++ binary_to_list(H),Tuple, List);
is_tuple(H)-> my_join(T,Binary ,Tuple ++ tuple_to_list(H), List);
is_list(H)-> my_join(T,Binary ,Tuple, List ++ H)
end;
my_join([],Binary, Tuple, List) ->
[list_to_binary(Binary),list_to_tuple(Tuple), List].
% 练习38 将列表中相同key的值进行合并,[{a,1},{b,2},{c,3},{b,4},{b,5},{c,6},{d,7},{d,8}]
-module(q_38).
-export([mix/1,is_re/2]).
is_re(Key, []) -> true;
is_re(Key, [H|T])->
if
element(1,H) == Key -> false;
element(1, H) /= Key -> is_re(Key, T)
end.
%遍历用element提出Key,在列表中用proplists:append_values来整合所有Key的值
mix(List) ->
mix(List, []).
mix([{K, V}|T], NewList)->
case is_re(K, NewList) of
true ->
%将整合后的Key值求和,并链接起来变为元组,加入新列表
Set_key = proplists:append_values(K, [{K,V}|T]),
KeyVal = [{K, lists:sum(Set_key)}],
mix(T, NewList ++ KeyVal);
false ->
mix(T, NewList)
end;
mix([], NewList) -> NewList.
39、Erlang程序设计(第2版)中5.3节的count_characters方法有错,自行修改证
count_characters(Str)->
count_characters(Str,#{}).
count_characters([H|T], X) ->
case maps:is_key(H,X)
of
false ->
count_characters(T, maps:put(H,1,X));
true -> Count = maps:get(H,X),
count_characters(T, maps:update(H,Count+1,X))
end;
count_characters([], X) ->
X.