LINUX.ORG.RU
решено ФорумTalks

erlang, жду критики.


0

2

Я изучаю erlang.

Задача: посчитать количество шестизначных чисел, в которых сумма первых трёх цифр совпадает с суммой вторых трёх цифр.

Решение:

-module(t2).
-export([two/0]).

two() ->
	N = lists:seq(0, 9),	
	L = [{A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N],
	count(L, 0).

count([], Sum) ->
	Sum;

count([H|T], Sum) ->
	{A, B, C, D, E, F} = H,
	if
		A+B+C == D+E+F ->
			count(T, Sum+1);
		true ->
			count(T, Sum)
	end.

жду критики, спасибо.

Ответ на: комментарий от x0r

Можно, если аргументированно. А что на счёт кода?

mi_estas
() автор топика

изучаю erlang

>Задача: посчитать количество шестизначных чисел, в которых сумма первых трёх цифр совпадает с суммой вторых трёх цифр.

Какая практичная задача! А главное без ерланга и поллитры здесь точно не разобраться.
Продолжай свой путь.

Bad_ptr ★★★★★
()
Ответ на: изучаю erlang от Bad_ptr

ты такой милый, спасибо на добром слове.

mi_estas
() автор топика

Операнды от операторов лучше пробелами отделять. Впрочем, это исключительно стилистическая придирка.

CARS ★★★★
()
Ответ на: комментарий от CARS

Операнды от операторов лучше пробелами отделять. Впрочем, это исключительно стилистическая придирка.

Все нормально у него, не гони.

power
()

if в коде на ерланге? отставить!

redixin ★★★★
()

> жду критики

[{A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N]

Выглядит просто замечательно, но всё же: man ленивые вычисления.

byte_size( term_to_binary([{A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N]) ).

14000007

По грубым подсчетам, расход памяти - 13,5 метров. На деле - намного больше. Когда дойдёшь до 1-2 кб, тогда уже можно показывать это на людях. В проекты такой код не пропустят.

shahid ★★★★★
()

зачем сначала генерить список, а потом по if обходить его? можно же генерировать список уже с условием.

count() ->
    N = lists:seq(0,9),
    Q = [ {A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N, A+B+C=:=D+E+F],
    list_len(Q,0).

list_len([],S) -> S;
list_len([_|T],S) -> list_len(T,S+1).

Kadi
()

типичная комбинаторная задача, которую уж точно не стоит решать перебором

aho
()
Ответ на: комментарий от mi_estas
(define (lucky? x)
  (let ((first-3-sum
	 (apply +
		(map
		 (lambda (c) (char->number c))
		 (string->list (substring (number->string x) 3)))))
	(last-3-sum
	 (apply +
		(map
		 (lambda (c) (char->number c))
		 (string->list (substring (number->string x) 0 3))))))
  (= first-3-sum last-3-sum)))
(filter lucky? (seq 100000 999999))

:)

power
()
Ответ на: комментарий от mi_estas

Сам изучаю, не встречался еще с length(), тогда еще проще.


count() ->
    N = lists:seq(0,9),
    length([ {A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N, A+B+C=:=D+E+F]).
Kadi
()
Ответ на: комментарий от power

Вот я об этом и говорил. Смотрю я на эти скобочки и вообще нифига не могу понять.

Вообще-то там в задаче номера лотерейных билетов были, и хотя 000001 вроде как не шестизначное число, но я так понял числа вида 1001 (или 1100, смысл я думаю понятен) тоже считать надо.

mi_estas
() автор топика
Ответ на: комментарий от mi_estas

В данном случае оно не надо.
=:= exactly equal to
== equal to

1> 2 == 2.0.
true
2> 2 =:= 2.0.
false

ates
()
Ответ на: комментарий от power

а если без char-ов и string-ов? :)

(do ((number 100000 (1+ number))
     (count 0))
    ((> number 999999) count)
  (when (= (+ (truncate (/ number 100000))
	      (- (truncate (/ number 10000)) (* 10 (truncate (/ (/ number 10000) 10))))
	      (- (truncate (/ number 1000)) (* 10 (truncate (/ (/ number 1000) 10)))))
	   (+ (- (truncate (/ number 100)) (* 10 (truncate (/ (/ number 100) 10))))
	      (- (truncate (/ number 10)) (* 10 (truncate (/ (/ number 10) 10))))
	      (- (truncate (/ number 1)) (* 10 (truncate (/ (/ number 1) 10))))))
    (incf count)))
Komintern ★★★★★
()
Ответ на: комментарий от Komintern

много глупых операций конечно, но на практике должно быть быстрее чем манипуляции с переводом типов.

Komintern ★★★★★
()
Ответ на: комментарий от mi_estas

да вот и сам чувсвую что что-то не так, но похоже ещё не дорос.

Правило-то простое. Данные в памяти должны появяться в памяти по мере наступления надобности оных, и ни наносекундой раньше. В контексте решения сабжевой задачи путем перебора списка - надо какбы проходить список, генеря каждый его элемент перед вызовом count(), а после вызова - отбрасывать пройденные элементы. Иными словами - никакого списка входных данных для скармливания в count() вообще быть не должно. Если хочется перебора, то проще решить эту задачу через рекурсию.

main() -> count({0,0,0,0,0,0}, []).


count({9,9,9,9,9,9}, Acc0) ->
   Acc0;
count({A,B,C,D,E,F}=E, Acc0) ->
   Acc1 = case A+B+C == D+E+F of
       true -> [E|Acc0];
       _    -> Acc0
   end,
   E1 = increment(E),
   count(E1, Acc1).

«A+B+C == D+E+F» можно вынести в заголовок функции.

shahid ★★★★★
()
Ответ на: комментарий от shahid

«A+B+C == D+E+F» можно вынести в заголовок функции.

count({9,9,9,9,9,9}, Acc0) ->
   Acc0;
count({A,B,C,D,E,F}=E, Acc0) when A+B+C == D+E+F ->
   count(increment(E), [E | Acc0]);
count(E, Acc0) ->
   count(increment(E), Acc0).
shahid ★★★★★
()
Ответ на: комментарий от mi_estas

> А что такое increment(E)?

Эта та функция, которую ты напишешь для того чтобы делать increment({0,0,0,0,0,0}) -> {0,0,0,0,0,1}, т.е. генерить следующий элемент списка из предыдущего.

Для переноса десятков можно сделать что-то типа:

increment({A,B,C,D,E,9}) ->... increment({A,B,C,D,9,F}) ->... ...

shahid ★★★★★
()
Ответ на: комментарий от power

схема. без if'ов, пожирания памяти, преобразований и лишних define'ов.

(let loop ((count 0) (now 100000))
  (or (and (= now 999999) count)
      (loop
       (+ count
          (or (and (apply
                    =
                    (map
                     (lambda (l)
                       (apply
                        +
                        (map
                         (lambda (n)
                           (- (truncate (/ now (expt 10 (- n 1))))
                              (* (truncate (/ (truncate (/ now (expt 10 (- n 1)))) 10)) 10)))
                         l)))
                     (list (list 1 2 3) (list 4 5 6))))
                   1)
              0))
       (+ now 1))))

drF_ckoff ★★
()
Ответ на: комментарий от mi_estas

Вот я об этом и говорил. Смотрю я на эти скобочки и вообще нифига не могу понять.

Да это просто я так пишу :) Да куча преобразований с толку сбивают. Вообще, лиспокод очень читаемый.

power
()
Ответ на: комментарий от shahid
%...
count({A,B,C,D,E,F}=E, Acc0) when A+B+C == D+E+F ->
   count(increment(E), [E | Acc0]);
%...

так все равно список формируется из всех элементов? чем этот способ лучше решения «влоб»?

[ {A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N, A+B+C==D+E+F ]

Kadi
()
Ответ на: комментарий от drF_ckoff

схема. без if'ов, пожирания памяти, преобразований и лишних define'ов.

И без читабельности.

Кстати, чем if не угодил?

power
()
Ответ на: комментарий от Kadi
 ... when A+B+C == D+E+F -> 
... [E | Acc0]

чем этот способ лучше решения «влоб»?

[ {A, B, C, D, E, F} || A<-N, B<-N, C<-N, D<-N, E<-N, F<-N, A+B+C==D+E+F ]

Тем, что в моём случае гарантировано длина стека вызова функции равна единице на протяжении всего перебора, и использование памяти минимально. Ваш лист-генератор разворачивается компилятором в набор списков, сочетаний fun и lists:map().

shahid ★★★★★
()
#include <cstdio>

int main( void )
{
    auto sum = [](int n) { int res = 0; for( ; n ; res += n % 10, n /= 10 ); return res; };

    int i, count = 0;
    for( i = 100000 ; i < 1000000 ; ++i )
        count += ( sum( i / 1000 ) == sum( i % 1000 ) );

    printf( "%d\n", count );
}

немного быдлокода на C++ для перебора

aho
()
Ответ на: комментарий от power

так же читабельно, как и твоё. то есть, на мой взгляд, абсолютно нечитабельно ни то ни другое.

ну там выше был вопль «if в коде на ерланге? отставить!», вот и сделал без if'ов.

drF_ckoff ★★
()

Немного экзотики (gforth):

\ найти все шестизначные десятичные числа ABCDEF, у которых: A+B+C == D+E+F
: sum%000   ( abc -- ) 10 /mod 10 /mod + + ;
: check%000 ( abcdef -- ) 1000 /mod sum%000 swap sum%000 = ;
: main 1000000 100000 ?do I check%000 if I . CR endif loop ;
main
BYE

Можно сохранить в файл test.fs и запустить так:
$ gforth ./test.fs | less

Neksys ★★★
()
Ответ на: комментарий от drF_ckoff

> Error: Optional arguments in LOOP don't match lambda list (&OPTIONAL (FIRST NIL CCL::FIRST-P) &REST REST).

While executing: (:INTERNAL CCL::NX1-COMPILE-LAMBDA), in process listener(1).


так-то =)

Komintern ★★★★★
()
Ответ на: комментарий от drF_ckoff

в целом подход похож на мой :)
кстати интересно потестить какой из подходов более производительный - через математику или через строки?

Komintern ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.