LINUX.ORG.RU

Функция «лесенка»

 , , jscript,


0

2

Натолкнулся на такой код на jscript

d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;

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

На лицо видно дупликация данных - каждое число по два раза. Как это максимально красиво написать? (на любом языке из популярных)

★★★★★

Последнее исправление: fornlr (всего исправлений: 1)

На любом языке? Не знаю как это насчёт популярных

let d = function (10|5|3|2) as i -> i | _ -> 1;;
List.map d ( 1--11 );;
- : int list = [1; 2; 3; 1; 5; 1; 1; 1; 1; 10; 1]

Ну а если душа просит изврата, то

let d a = 
   try
      List.find ((=)a) [10;5;3;2]
   with
      | Not_found -> 1
;;

anonymous
()
Ответ на: комментарий от SystemD-hater

ты прав, однако, x ?: y == x ? x : y, что то я поленился подумать.

AndreyKl ★★★★★
()

Значений мало, вроде забыли константный мэппинг:

unsigned int
get_switch_d( unsigned int d )
{
	switch(d)
	{
		case 0:
		case 1: return 1;
		case 2: return 2;
		case 3:
		case 4: return 3;
		default: 
			if (d>=10) return 10; 
			else return 5;
	}
}

unsigned int
get_array_d( unsigned int d )
{
	const int a[] = {1,1,2,3,3,5,5,5,5,5};
	return d >=10 ? 10 : a[d];
}
bsivko
()
(defmacro lesenka (fn n &rest args)
  (lw:rebinding (n)
    (labels ((gen-if (x rest)
               (if (endp rest)
                   `,x
                   `(if (,fn ,n ,x)
                        ,x
                        ,(gen-if (first rest) (rest rest))))))
      (if (null args)
          `,n
          (gen-if (first args) (rest args))))))
CL-USER> (macroexpand '(lesenka >= 7 10 5 3 2 1))
(LET* ((#:N239460 7))
  (IF (>= #:N239460 10)
      10
      (IF (>= #:N239460 5)
          5
          (IF (>= #:N239460 3)
              3
              (IF (>= #:N239460 2)
                  2
                  1)))))
CL-USER> (lesenka >= 7 10 5 3 2 1)
5
CL-USER> (lesenka >= 7 1)
1
CL-USER> (lesenka >= 7)
7
Oxdeadbeef ★★★
()
(or (value-if-cond d >= 10) (value-if-cond d >= 5) (value-if-cond d >= 3) (value-if-cond d >= 2) 1)
anonymous
()
Ответ на: комментарий от anonymous

Что по скорости будет равно изначальному варианту.

Цикл - это дополнительный кондишн. Так что гарантировать «равно изначальному варианту» нельзя.

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

Эээ, а во что этот case с INT_MAX скомпилируется? 😲

if(d >= 10 && d <= INT_MAX) {}

andreyu ★★★★★
()

picolisp

(setq D (or (find '((X)(<= X D)) (10 5 3 2)) 1))
anonymous
()

Тоже вброшу

>>> [(x>=1) * next((n for n in (10, 5, 3, 2, 1, x) if x>=n)) or False for x in [-2, 3.14, 4.2, *range(12)]]
[False, 3, 3, False, 1, 2, 3, 3, 5, 5, 5, 5, 5, 10, 10]
anonymous
()
Ответ на: комментарий от anonymous

или for (const auto& it : steps)
предыдущим сообщением просто хотел сказать что есть range-based циклы, которыми удобнее пользоваться.

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

возьми да посмотри

Так на смартфоне компилятора то нет. Посмотрел - прикольно, хотя как-то странно все равно выглядят в Си бесконечные интервалы. У меня бы копыта такое не поднялись бы написать.

fornlr ★★★★★
() автор топика

Извините, на специальную олимпиаду здесь записывают? Тогда вот вам короткий и относительно читаемый вариант.

d = [10,5,3,2,1].filter(e => d >= e)[0]

Главный минус - он не ленив, в отличие от ОП-поста. Ну и фэйлит на d < 1.

unikoid ★★★
()
Последнее исправление: unikoid (всего исправлений: 1)
Ответ на: комментарий от unikoid

Очевидный патч очевиден:

d = [10,5,3,2,1].filter(e => d >= e)[0] || 1;

Очевидный ленивый вариант - также.
var values = [10,5,3,2,1];
var till = values.length-1;
for(var i=0; i<till && d<values[i]; i++) {}
d = values[i];

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

И говнокод на закуску:

check(Val, [Head]) -> Head;
check(Val, [Head|Tail]) when Val >= Head -> Head;
check(Val, [Head|Tail]) -> check(Val, Tail).

unikoid ★★★
()
Ответ на: комментарий от Oxdeadbeef
(defmacro lesenka (fn n &rest args)
  (lw:rebinding (fn n)
    (labels ((gen-if (x rest)
               (if (endp rest)
                   `,x
                   (lw:rebinding (x)
                     `(if (funcall ,fn ,n ,x)
                          ,x
                          ,(gen-if (first rest) (rest rest)))))))
      (if (null args)
          `,n
          (gen-if (first args) (rest args))))))
CL-USER> (macroexpand '(lesenka #'>= 7 10 5 3 2 1))
(LET* ((#:FN233301 #'>=) (#:N233302 7))
  (LET* ((#:X233303 10))
    (IF (FUNCALL #:FN233301 #:N233302 #:X233303)
        #:X233303
        (LET* ((#:X233304 5))
          (IF (FUNCALL #:FN233301 #:N233302 #:X233304)
              #:X233304
              (LET* ((#:X233305 3))
                (IF (FUNCALL #:FN233301 #:N233302 #:X233305)
                    #:X233305
                    (LET* ((#:X233306 2))
                      (IF (FUNCALL #:FN233301 #:N233302 #:X233306)
                          #:X233306
                          1)))))))))
CL-USER> (macroexpand '(lesenka #'(lambda (x y) (>= x y)) 7 (+ 4 6) (+ 2 3) 3 2 1))
(LET* ((#:FN233697 #'(LAMBDA (X Y) (>= X Y))) (#:N233698 7))
  (LET* ((#:X233699 (+ 4 6)))
    (IF (FUNCALL #:FN233697 #:N233698 #:X233699)
        #:X233699
        (LET* ((#:X233700 (+ 2 3)))
          (IF (FUNCALL #:FN233697 #:N233698 #:X233700)
              #:X233700
              (LET* ((#:X233701 3))
                (IF (FUNCALL #:FN233697 #:N233698 #:X233701)
                    #:X233701
                    (LET* ((#:X233702 2))
                      (IF (FUNCALL #:FN233697 #:N233698 #:X233702)
                          #:X233702
                          1)))))))))
CL-USER> (lesenka #'>= 7 10 5 3 2 1)
5
CL-USER> (lesenka #'(lambda (x y) (>= x y)) 7 (+ 4 6) (+ 2 3) 3 2 1)
5
CL-USER> (lesenka #'>= 7 1)
1
CL-USER> (lesenka #'>= 7)
7
Oxdeadbeef ★★★
()
Ответ на: комментарий от Oxdeadbeef

Да почему каждый школьник на лоре требует написать функцию вычисления факториала (или подобную) для доказательства знаний?

Ну ладно, смотри.

(defun make-step-function (list)
  (lambda (x)
    (let ((position (position x list :test #'>= :from-end t)))
      (if position (nth position list) (car list)))))

Макросы нужны для кодогенерации, а здесь обычная функция (в математическом смысле этого слова)

anonymous
()
{$burn-ass on}
{$define _if:= else if d >=}
{$define _to:= then d:=}

if d >= 10 _to 10 _if 5 _to 5 _if 3 _to 3 _if 2 _to 2 else d:=1;
superuser ★★★★★
()
Последнее исправление: superuser (всего исправлений: 2)
Ответ на: комментарий от anonymous

Макросы нужны для кодогенерации

a если мне нужна ленивость: cледущий меньший интервал вытаскивается из сети или вычисляется сутками?

Моя макра сработает. Твой вариант — простой, для ТС подойдет, не спорю.

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

cледущий меньший интервал вытаскивается из сети или вычисляется сутками?

Ты стартовое сообщение хорошо увидел? В общем, решил ты выпендриться с макрой, выпендрился, но публика не удивлена. Лучше не выпендриваться, я тебе скажу

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

В общем, решил ты выпендриться с макрой

Нет, я решил порекламировать фичи лиспа, а у кого-то загорелось.

выпендрился, но публика не удивлена.

Пиар удался на славу, у кого-то бомбануло.

Лучше не выпендриваться, я тебе скажу

Лучше не указывай мне, что делать, я тебе скажу.

Oxdeadbeef ★★★
()
O_O:
    .quad   0,1,2,3,3,5,5,5,5,5

lesenka:
    cmp     rax,    10
    jl      do_it
    mov     rax,    10
    ret

do_it:
    mov     rax,   QWORD PTR [O_O + rax*8]
    ret

подрочил слегка

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

Ну ладно, смотри.

Да почему каждый школьник на лоре требует написать функцию вычисления факториала (или подобную) для доказательства знаний?

Ну ладно, смотри.

(defun lesenka (fn n &rest args)
  (reduce #'(lambda (x y)
              (if (funcall fn x y)
                  (return-from lesenka y)
                  x))
          args
          :initial-value n))
CL-USER> (lesenka #'>= 7 10 5 3 2 1)
5
CL-USER> (lesenka #'>= 7 1)
1
CL-USER> (lesenka #'>= 7)
7
anonymous
()

js:

for (i in v = [10,5,3,2,1]) if (d >= v[i]) break;
d = v[i];

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

Perl крут. А как это работает?

$d = (grep { $d >= $_ } (10,5,3,2))[0] // 1;

Смысл тот же что и в решении для Java. Сначала выбираются значения удовлетворяющие условию “d >=" с помощью grep, затем выбирается первое из них («[0]”). Если ни одно из условий не подходит (пустой список), то присвоить d значение “1”.

necromant ★★
()

asm

step(int, int const*, unsigned long):                           # @step(int, int const*, unsigned long)
	movl	(%rsi), %r8d
	movl	$1, %ecx
	testq	%rdx, %rdx
	je	.LBB0_1
	cmpl	%edi, %r8d
	jle	.LBB0_3
.LBB0_4:                                
	movl	%r8d, %eax
	cmpq	%rdx, %rcx
	jae	.LBB0_6
	movl	(%rsi,%rcx,4), %r8d
	incq	%rcx
	cmpl	%edi, %r8d
	jg	.LBB0_4
.LBB0_6:                                
	retq
.LBB0_1:
	movl	%r8d, %eax
	retq
.LBB0_3:
	movl	%r8d, %eax
	retq

main:                                  
	pushq	%rax
	movl	$.L.str, %edi
	movl	$10, %esi
	xorl	%eax, %eax
	callq	printf
	xorl	%eax, %eax
	popq	%rdx
	retq

.L.str:
	.asciz	"%d\n"
CyberK
()

Ну что, по краткости моё решение ещё никто не переплюнул? ;)

      step←{⍺[+/⍵∘.≥⍺]}
      1 2 3 5 10 step ⍳15
1 2 3 3 5 5 5 5 5 10 10 10 10 10 10
PS: APL рулит :D

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 2)

Free Pascal + asm:

function lesenka(d: integer; const arr: array of integer): integer; assembler; register;
asm
        CMP ECX, 0
        JL  @@E

@@LOOP: MOV EBX, [EDX]
        CMP EAX, EBX
        JNL @@R
        DEC ECX
        JL  @@R
        ADD EDX, 4
        JMP @@LOOP

@@R:    MOV EAX, EBX
@@E:
end;

...
  d := lesenka(d, [10, 5, 3, 2, 1]); 

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

Как у ТС в примере (или смотри мою макру), где ELSE ветка будет вычисляться по-необходимости.

PS: Есть ли открытые полные реализации АПЛ? Компиляторы? По твоей ссылке АПЛ-вендоры просят продаться в рабство за использование в коммерческих целях.

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

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

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