【问题标题】:multiplication of two list using list -erlang使用 list -erlang 将两个列表相乘
【发布时间】:2017-05-15 07:42:14
【问题描述】:

如何将列表中表示的两个数字相乘,例如123 * 12 = 1476 我想在这个例子中使用列表来做这个操作它应该是这样的 mul([1,2,3],[1,2]) 结果将是 [1,4,7,6] 而不使用 list_to_integer 函数将列表转换为数字。到目前为止我已经这样做了,但是如果列表之一的长度等于 1,它就可以正常工作

mul([],A) ->[];
mul(A,[]) ->[];
mul([H|T],B) -> 
             if

    (length([H|T]) ==1) or (length(B)== 1)
                                        ->
                                        [X*Y||X<-[H],Y<-B]++mul(T,B);



        (length([H|T]) >1) or (length(B) > 1)                               

                                            -> 
                                             [X*Y||X<-[H],Y<-B]++mul(T,B)

     end.

【问题讨论】:

  • 你能告诉我们你到目前为止尝试了什么以及你得到了什么结果吗?
  • @SteveVinoski 我已经发布了我所做的...
  • 请注意,[X*Y || X&lt;-[H] , Y&lt;-B] 等同于 [H*Y|| Y&lt;-B],因为 H 是列表中的一个数字,而不是列表本身。

标签: erlang


【解决方案1】:

例如,所以:

multi(List, N) when is_number(N) ->
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * N * pow10(Index), Index + 1} end,
      {0, 0}, List));
multi(L1, L2) when is_list(L2) ->
  List = [fun() -> multi(L1, X) end() || X <- L2],
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * pow10(Index), Index + 1} end,
      {0, 0}, List)).

pow10(N) when N =:= 0 -> 1;
pow10(N) -> 10 * pow10(N - 1).

如果注意到foldr表达式相似,可以简化代码:

multi(List, N) when is_number(N) ->
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * N * pow10(Index), Index + 1} end,
      {0, 0}, List));
multi(L1, L2) when is_list(L2) ->
  multi([fun() -> multi(L1, X) end() || X <- L2], 1).

pow10(N) when N =:= 0 -> 1;
pow10(N) -> 10 * pow10(N - 1).

获取列表,使用 integer_to_list:

...
multi(L1, L2) when is_list(L2) ->
 create_list(multi([fun() -> multi(L1, X) end() || X <- L2],1)).

create_list(Number)->
  [X-48 || X<-integer_to_list(Number)].
...

【讨论】:

  • 非常感谢@Atomic,它工作得很好,如果我想在列表中表示结果,例如multi([43],[1,7]). 结果变成[7,3,1] 状态为731,它将如何。
  • @koko,你说得对,我的注意力不集中。之后可以用 integer_to_list 拆分吗?
  • 非常感谢@Atomic 我已经解决了那部分(将结果转换为列表)..但是您的解决方案比我的解决方案效率高。
【解决方案2】:

这是不使用list_to_integerinteger_to_list 的解决方案。算法称为long multiplication,通常在语言不支持大(大于 INT.MAX)数字的乘法/求和时使用。以下是可以通过各种方式进行优化的基本实现,但可以很好地用于教育目的。

请记住,Erlang 支持开箱即用的长乘法和长和(与 C 相对),因此在现实生活中实现乘法是没有用的应用程序。

sum(A, B) when is_list(A) andalso is_list(B) -> 
  lists:reverse(sum_impl(lists:reverse(A), lists:reverse(B), {[], 0})).
mult(A, B) when is_list(A) andalso is_list(B) -> 
  lists:reverse(mult_impl(lists:reverse(A), lists:reverse(B), {[], []})).

sum_impl([], [], {Res, 0}) -> Res;
sum_impl([], [], {Res, C}) -> sum_impl([C], [0], {Res, 0});
sum_impl(A, [], Acc) -> sum_impl(A, [0], Acc);
sum_impl([], B, Acc) -> sum_impl([0], B, Acc);
sum_impl([HA | TA], [HB | TB], {Res, C}) ->
  sum_impl(TA, TB, {Res ++ [(HA + HB + C) rem 10], (HA + HB + C) div 10}).

mult_impl(_A, [], {Res, _C}) -> Res;
mult_impl(A, [HB | TB], {Res, C}) ->
  mult_impl(A, TB, {sum_impl(Res, C ++ [X * HB || X <- A], {[], 0}), [0 | C]}).

【讨论】:

    【解决方案3】:

    这是一个允许您指定基数 (2-10) 的版本:

    在外壳中:

    167> c(my).                                    
    {ok,my}
    
    168> Base10 = 10.                              
    10
    169> Base2 = 2.
    2
    
    170> my:list_mult([1,1], [1,1,1], Base10).       
    [1,2,2,1]
    171> 11 * 111.                            
    1221
    
    
    172>  my:list_mult([1,1], [1,1,1], Base2). 
    [1,0,1,0,1]
    173> io:format("~.2B~n", [2#11 * 2#111]).       
    10101
    ok
    

    -module(my).
    %%-compile(export_all).
    -export([list_mult/3]).
    -include_lib("eunit/include/eunit.hrl").
    
    list_mult(List1, List2, Base) ->
        Number = digits_to_int(List1, Base) * digits_to_int(List2, Base),
        list_of_digits(Number, Base).
    
    list_mult_test() ->
        Base10 = 10,
        ?assertEqual( 
            list_of_digits(123 * 12, Base10), 
            list_mult([1,2,3], [1,2], Base10)
        ),
        ?assertEqual(
            list_of_digits(2 * 5, Base10),
            list_mult([2], [5], Base10)
        ),
        ?assertEqual(
            list_of_digits(0 * 0, Base10),
            list_mult([], [], Base10)
        ),
        ?assertEqual(
            list_of_digits(0 * 23, Base10),
            list_mult([], [2,3], Base10)
        ),
        ?assertEqual(
            list_of_digits(30 * 4, Base10),
            list_mult([0,3,0], [0,4], Base10)
        ),
        ?assertEqual(
            list_of_digits(1 * 3, Base10), 
            list_mult([0,0,1], [0,3], Base10)
        ),
    
        Base2 = 2,
        ?assertEqual(
            list_of_digits(2#11 * 2#1000, Base2), 
            list_mult([1,1], [1,0,0,0], Base2)
        ),
        ?assertEqual(
            list_of_digits(2#1001 * 2#10, Base2),
            list_mult([1,0,0,1], [1,0], Base2)
        ),
    
        %%Errors:
        ?assertThrow(
           "illegal_number: Some elements are >= to Base",
           list_mult([1,3], [1,0,0,0,0], Base2)
        ),
        ?assertThrow(
           "illegal_number: Some elements are >= to Base",
           list_mult([a, 3], [f,1], Base10)  %%hex notation
        ).    
    
    %--------------
    
    digits_to_int_test() ->
        Base10 = 10,
        ?assertEqual(
           123,
           digits_to_int([1,2,3], Base10)
        ),
        ?assertEqual(
           10,
           digits_to_int([1,0], Base10)
        ),
        ?assertEqual(
           3,
           digits_to_int([3], Base10)
        ),
        ?assertEqual(
           0,
           digits_to_int([0], Base10)
        ),
        ?assertEqual(
           0,
           digits_to_int([], Base10)
        ),
    
        Base2 = 2,
        ?assertEqual(
           2#11,
           digits_to_int([1,1], Base2)
        ),
        ?assertEqual(
           2#1101,
           digits_to_int([1,1,0,1], Base2)
        ),
        ?assertEqual(
           2#11110000,
           digits_to_int([1,1,1,1, 0,0,0,0], Base2)
        ),
        ?assertEqual(
           2#1,
           digits_to_int([1], Base2)
        ),
        ?assertEqual(
           0,
           digits_to_int([0], Base2)
        ),
        ?assertEqual(
           0,
           digits_to_int([], Base2)
        ),
        %%Errors:
        ?assertThrow(
           "illegal_number: Some elements are >= to Base",
           digits_to_int([1,2,3], Base2)
        ),
        ?assertThrow(
           "illegal_number: Some elements are >= to Base",
           list_mult([a, 3], [f,1], Base10)  %%hex notation
        ).    
    
    digits_to_int(List, Base) ->
        HighestPower = length(List) - 1,
        digits_to_int(List, Base, HighestPower, 0).
    
    digits_to_int([], _, _, Sum) ->
        Sum;
    digits_to_int([X|Xs], Base, Power, Sum) when X<Base ->
        Term = round( math:pow(Base, Power) * X ),  %%round() converts float to integer. 
        digits_to_int(Xs, Base, Power-1, Sum+Term);
    digits_to_int(_, _, _, _) ->
        throw("illegal_number: Some elements are >= to Base").
    
    %--------------
    
    list_of_digits_test() ->
        Base10 = 10,
        ?assertEqual(
            [1,1],
            list_of_digits(11, Base10)
          ),
        ?assertEqual(
            [1,0,0],
            list_of_digits(100, Base10)
          ),
        ?assertEqual(
            [1],
            list_of_digits(1, Base10)
          ),
        ?assertEqual(
            [],
            list_of_digits(0, Base10)
          ),
    
        Base2 = 2,
        ?assertEqual(
            [1,0,1,1],
            list_of_digits(2#1011, Base2)
          ),
        ?assertEqual(
            [1,1,1],
            list_of_digits(2#111, Base2)
          ),
        ?assertEqual(
            [1],
            list_of_digits(1, Base2)
          ).
    
    list_of_digits(0, _Base) ->
        [];
    list_of_digits(Number, Base) -> %% 193
        HighestPower = get_highest_power(Number, Base),
        list_of_digits(Number, Base, HighestPower, []).
    
    list_of_digits(Number, _, 0, Digits) ->
        lists:reverse([Number|Digits]);
    list_of_digits(Number, Base, Power, Digits) ->
        X = round(math:pow(Base, Power) ),
        Digit = Number div X,
        Remainder = Number rem X,
        list_of_digits(Remainder, Base, Power-1, [Digit|Digits]).
    
    %---------------
    
    get_highest_power_test() ->
        Base10 = 10,
        ?assertEqual(
            2,
            get_highest_power(199, Base10)
          ),
        ?assertEqual(
            3,
            get_highest_power(1999, Base10)
          ),
        ?assertEqual(
            3,
            get_highest_power(1000, Base10)
          ),
        ?assertEqual(
            1,
            get_highest_power(19, Base10)
          ),
        ?assertEqual(
            0,
            get_highest_power(5, Base10)
          ).
    
    get_highest_power(Number, Base) ->
        Power = 0,
        KeepGoing = (Number div round(math:pow(Base,Power)) ) > 0,
        get_highest_power(Number, Base, Power, KeepGoing).
    
    get_highest_power(Number, Base, Power, KeepGoing) when KeepGoing =:= true ->
        NewPower = Power+1,
        StillKeepGoing = (Number div round(math:pow(Base, NewPower)) ) > 0,
        get_highest_power(Number, Base, NewPower, StillKeepGoing); 
    get_highest_power(_, _, Power, KeepGoing) when KeepGoing =:= false ->
        max(0, Power - 1).
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-05
      • 2021-09-21
      相关资源
      最近更新 更多