LINUX.ORG.RU

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

 , , jscript,


0

2

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

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

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

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

★★★★★

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

#define step(x, val) (x)>=(val) ? (val) :

И #define laststep(x, val1, val2) (x)>=(val1) ? (val1) : (val2)
Получится d = step(d, 10) step(d, 5) step(d, 3) laststep(d, 2, 1)
Но это сишная ересь, лучше делать универсальные циклы.

Northsoft ★★
()

Здесь несколько тернарных операторов, чем вас не устраивает этот код? Можно переписать используя if-else, но тогда говнокода будет много.

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

Не устраивает то, что задавая узлы: 2,3,5,10 - они пишутся по два раза

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

чем вас не устраивает этот код?

Он нечитабелен.

Можно переписать используя if-else, но тогда говнокода будет много.

Странные представления о понятии «говнокод».

GoodPerson
()

c++

#include <cstdio>
#include <cassert>

int step(int value, const int * steps, size_t step_count)
{
  assert(steps);
  assert(step_count > 0);

  int curr_step = steps[0];

  for (size_t i = 0; i < step_count; ++i)
  {
    if (steps[i] > value)
      curr_step = steps[i];
    else
      break;
   }

  return curr_step;
}


int main()
{
  constexpr size_t step_count = 5;
  int steps[step_count] = { 20, 10, 4, 1, 0 };

  for (int i = -5; i < 30; ++i)
  {
    int result = step(i, steps, step_count);
    printf("For %d result is %d. \n", i, result);
  }
	
  return 0;
}
CyberK
()

js

function check ( d ) {
	i = 10;
	do {
		if (d >= i) {
			return i;
		}
		i = (i - i % 2) / 2;
	} while (i >= 1);
}

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

Python:

a=np.array([11,12,13])
f = lambda x: 1 if len(find(x>=a))==0 else a[find(x>=a)][-1]

Bell
()
Ответ на: c++ от CyberK

Какой же это С++ ?

Надо хотя бы так писать:

template <typename ArrayT, typename T>
T step(T value, ArrayT&& _steps)
{
  assert(begin(_steps) != end(_steps));

  const ArrayT& steps = _steps;

  auto curr_step = steps[0];

  for (auto it = begin(steps); it != end(steps); it++)
  {
    if (*it > value)
      curr_step = *it;
    else
      break;
   }

  return curr_step;
}
anatoly
()

на «любом из языков» бывает есть возможность определить такой оператор

?:
т.е. пишешь просто
d = d >= 10 ?: d >= 5 ?: d >= 3 ?: d >= 2 ?: 1

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

Можно и так

Я просто стараюсь избегать темплатов там где они не сильно нужны. А то они сильно увеличивают время компиляции на огромных проектах. И сильно раздувают размер executable.

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

а вообще вот это красиво, для любого количества чисел одинаковое число строк. плюсую, крутой код.

AndreyKl ★★★★★
()

Как это максимально красиво написать?

Как по мне - и так красиво. Можно завернуть всю эту бороду в функцию конечно, а если эта штука встречается больше 1 раза - то нужно.

no-such-file ★★★★★
()

Держи короткий красивый код. Вроде даже работает.

d = [10,5,3,2,1].reduce(function(p,c,i,a){return a.indexOf(p)>=0?p:(p>c?c:p);},d);
amomymous ★★★
()
Ответ на: комментарий от anatoly

Дура ты. На С++ оно будет либо как у ТС, либо где-то так:

auto foo = []( int v ) 
{
    for( int i : { 10, 5, 3, 2 } )
    {
        if( v >= i )
            return i;
    }
    
    return 1;
};

d = foo( d );

Что по скорости будет равно изначальному варианту. Можно было бы сделать и как в примере на Java, но в С++ не поощряется использование неэффективного кода (а там сразу виден оверхед).

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

красивый код
d = [10,5,3,2,1].reduce(function(p,c,i,a){return a.indexOf(p)>=0?p:(p>c?c:p);},d);

У ТС на порядок красивей и понятней код.

anonymous
()

Вот элегантный удобочитаемый код

   a =: {:@:(>#])
   b =: (a&1 3 7 10)
   (b"0)@i. 12
0 0 1 1 3 3 3 3 7 7 7 10
anonymous
()
#define QC(x) d >= x ? x :
d = QC(10) QC(5) QC(3) QC(2) 1;

Те же яйца, только писать длинное условие будет проще.

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

без дупликации данных


Number.prototype._ = function(n){
  if(this >= n) throw n; return this.valueOf()
}

try{ d._(10)._(5)._(3)._(2)._(1) }catch(n){d = n}

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

В данном случае, эффективность заключается только лишь в нелокальном выходе, и только в нем. Внезапно, разного рода балансировщики деревьев и прочее хаскель-подобное говно как раз этого не умеет.

newquestion
()

Если ограничиться только последовательностью int-ов, которая зафиксирована на этапе компиляции, то на C++11/14 можно так:

#include <iostream>

template< int a, int... vals >
struct step {
	static constexpr int value( int d ) {
		return d >= a ? a : step< vals... >::value(d);
	}
};

template<int a>
struct step<a> {
	static constexpr int value( int ) { return a; }
};

int main()
{
	using step_check = step< 10, 5, 3, 2, 1 >;
	std::cout << "12: " << step_check::value(12) << std::endl;
	std::cout << "7: " << step_check::value(7) << std::endl;
	std::cout << "5: " << step_check::value(5) << std::endl;
	std::cout << "4: " << step_check::value(4) << std::endl;
	std::cout << "3: " << step_check::value(3) << std::endl;
	std::cout << "2: " << step_check::value(2) << std::endl;
	std::cout << "1: " << step_check::value(1) << std::endl;
	std::cout << "0: " << step_check::value(0) << std::endl;
	std::cout << "-1: " << step_check::value(-1) << std::endl;
}
В данном случае все вычисления будут выполняться в compile-time.

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

спасиб

У этого array_view дикий оверхед (https://github.com/Microsoft/GSL/blob/master/include/array_view.h), и к тому же ему всё равно нужно передавать количество элементов в конструктор, так что я просто перетащу проблему на другой уровень, где я могу сделать такую же ошибку. И как я уже написал выше, я предпочитаю не использовать темплэйты где не обязательно. Так что в этом конкретном случае это был мой осознанный выбор. Но всё равно спасибо за инфу.

CyberK
()
Ответ на: спасиб от CyberK

У этого array_view дикий оверхед

Это где именно вы там оверхед нашли, да еще и дикий?

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

const int *, size_t

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

по сравнению с просто поинтером на array, в этом конкретном простом примере это дикий оверхед который не несет с собой никакого added value. результат же тот же, только больше работы чтоб его достичь. я не против темплейтов, но в данном случае это просто не нужно было.

CyberK
()
Ответ на: спасиб от CyberK

Вообще-то этот array_view спроектирован так, чтобы оверхеда не было. Это во-первых. Во-вторых, даже без него существуют контейнеры, которые специально придуманы в прошлом веке как раз чтобы избавиться от таких вот ублюдочных интерфейсов (которые и тогда уже были ублюдочными).

asaw ★★★★★
()
Ответ на: const int *, size_t от CyberK

const int *, size_t

Вы так тонко троллить пытаетесь? Посмотрите в прототип своей же функции:

int step(int value, const int * steps, size_t step_count)

В ран-тайме оверхед точно такой же.

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

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

я негде не упоминал рантайм, я просто сказал что в данном конкретном случае я считаю что это было не обязательно. Спор не о чем, что вы пытаетесь доказать? что array_view это хорошо? Я и не против, но в данном примере это просто не нужно.

CyberK
()

[10, 5, 3, 2, 1].find(function (i) { return d >= i })

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

я негде не упоминал рантайм

Термин «оверхед» чаще всего используется применительно к ран-тайму, а не к компайл-тайму.

что вы пытаетесь доказать?

Что вы посмотрели в код array_view и увидели какие-то собственные фобии.

но в данном примере это просто не нужно.

Это вам так кажется. Замените в своем коде значение stop_count, например, с 5 на 6, ничего не меняя больше, и вы получите баг, который будет диагностирован только в run-time. А вот если бы вы использовали array_view и написали бы вот так:

int steps[] = { 20, 10, 4, 1, 0 };

for (int i = -5; i < 30; ++i)
{
  int result = step(i, steps);
  printf("For %d result is %d. \n", i, result);
}
То шансов внести ошибку при сопровождении кода было бы значительно меньше. Для этого, собственно, array_view и создали.

eao197 ★★★★★
()
from bisect import bisect

def f(array, x):
    """
    >>> f([1,2,3,5,10], 0)
    1
    >>> f([1,2,3,5,10], 1)
    1
    >>> f([1,2,3,5,10], 2)
    2
    >>> f([1,2,3,5,10], 3)
    3
    >>> f([1,2,3,5,10], 4)
    3
    >>> f([1,2,3,5,10], 5)
    5
    >>> f([1,2,3,5,10], 6)
    5
    >>> f([1,2,3,5,10], 9)
    5
    >>> f([1,2,3,5,10], 10)
    10
    >>> f([1,2,3,5,10], 11)
    10
    """
    return array[max(0, bisect(array, x) - 1)]
MyTrooName ★★★★★
()
Ответ на: комментарий от eao197

А если бы то, а если бы это, но в конце концов же там написано 5 а не шесть, ладно, это уже совсем не интересно, просто скучно, и вам хочется спорить зачем-то, бай. мне это уже совсем не интересно. всего хорошего :)

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

Вот ещё такой вариант:

      n←1 3 5 7 10
      m←⍳12
      n[+/ m ∘.≥ n]
1 1 3 3 5 5 7 7 7 10 10 10

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

и вам хочется спорить зачем-то

Мне хочется, чтобы код на C++ был кодом на C++, а не на C (в вашем примере как раз C-шный код, но написанный с использованием C++ного API). C++ же последние лет 20 развивается в том направлении, чтобы как можно больше ошибок исключить еще в компайл-тайм. Тот же самый GSL — это один из хороших примеров того, как именно это происходит и чем следует пользоваться в современном C++.

eao197 ★★★★★
()

что-то не видать хашкелистов. странно.

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

Мне хочется, чтобы код на C++ был кодом на C++, а не на C

Самое непонятное зачем так писать, ибо тот код в два счёта можно сделать нормальным чистым СИшным. На такой суржик нужен...

fornlr ★★★★★
() автор топика
Последнее исправление: fornlr (всего исправлений: 3)

этот тред наполнен ненавистью и попаболью?

теги c++, java

по итогам конкурса: Io поимел все представленные языки, как всегда. Второе место присуждается JS.

Ё.

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

Дык в том-то и дело. Из C++ там только имена залоговочных файлов и непонятно зачем приткнутый constexpr, хотя хватило бы и обычного const.

eao197 ★★★★★
()

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

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

x ?: y эквивалентно x ? x : y; поэтому выражение d >= 10 ?: <всё остальное>; при d >= 10 будет иметь значение (d >= 10), т.е. true, что при присвоении целочисленной переменной даст единицу.

Разве нет?

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