devclub.eu quiz

Задание: Напечатать на экране следующее:
1
2-1
1-2-3
4-3-2-1
1-2-3-4-5
6-5-4-3-2-1
(Естественно, вместо 6 может быть любое число).
Большинство решений вообщем-то похожи, разница лишь в синтаксисе (и функциях, которые доступны в языке). Все решения стремятся к "one-line solution" ну и благодаря своей динамичности и хорошей библиотеке пока большинством признано решение на Groovy (Сергей Кирьянов):
for ( i in 1..10 ) println( ( i%2 ? 1..i : i..1 ).join('-') );
С моей же точки зрения, если взять за основу, что мы выводим текст на консоль и N не может быть слишком большим, то совершенно гениальным решением является код от Ильи Хямяляйнена (который он кстати сам считает WTF-кодом):
System.out.print("1"); System.out.print("2-1"); System.out.print("1-2-3"); System.out.print("4-3-2-1"); System.out.print("1-2-3-4-5"); System.out.print("6-5-4-3-2-1");
Впрочем, на джаве это действительно выглядит ужастно, хоть и читаемо лучше всех решений :) К счастью, у нас есть Clojure, который умеет генерить такого рода штуковины.
Итак, задача сведется к тому, чтобы выводить на экран ряды из цифр, перевернутные через раз. Цифры печатаются через знак "-". Т.е. код может выглядеть так:
(do (println (str-join "-" (range 1 2))) (println (str-join "-" (reverse-range 1 3))) (println (str-join "-" (range 1 4))) (println (str-join "-" (reverse-range 1 5))) (println (str-join "-" (range 1 6))) (println (str-join "-" (reverse-range 1 7))))
Сделаем это через макросы:
(ns foo (:use clojure.contrib.str-utils)) (defn reverse-range [start end] (reverse (range start end))) (defmacro ranger [size] (let [func (cycle [`range `reverse-range])] (cons 'do (for [step (range 2 (+ 2 size))] `(println (str-join "-" (~(nth func step) 1 ~step)))))))
Выглядит страшнее, чем код на груви, но читабельность, как ни странно, сохранена - любой программист сможет всегда вызывать macroexpand и понять, как работает тот или иной макрос:
foo> (macroexpand '(ranger 3)) (do (clojure.core/println (clojure.contrib.str-utils/str-join "-" (clojure.core/range 1 2))) (clojure.core/println (clojure.contrib.str-utils/str-join "-" (foo/reverse-range 1 3))) (clojure.core/println (clojure.contrib.str-utils/str-join "-" (clojure.core/range 1 4))))
Ну и, собственно, демка (все работает:) ):
foo> (ranger 6) 1 2-1 1-2-3 4-3-2-1 1-2-3-4-5 6-5-4-3-2-1
|
</> |