Erlang考核练习题

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.

推荐阅读 更多精彩内容