1. C# / Говнокод #9995

    +958

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    public int RomeToArab (string str)
    {
    	int[] arabian = new int[13] { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
    	strint[] rome = new string[13] { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
    	int n = 0;
    	int i = 0;
    	do
    	{
    		if (str.StartsWith(rome[i]))
    		{
    			n = n + arabian[i];
    			str = str.Substring(rome[i].Length, str.Length - rome[i].Length);
    		}
    		if (!str.StartsWith(rome[i])
    			i++;
    	}
    	while (i < 13);
    	return n;
    }

    Запостил: aleksi, 20 Апреля 2012

    Комментарии (16) RSS

    • Рим к Арабам
      Ответить
    • (defun roman-to-arabic (numeral)
        (labels
            ((parse (i x)
      	 (if (< i 0) x
      	     (let ((y
      		    (ccase (aref numeral i)
      		      ((#\i) 1)
      		      ((#\v) 5)
      		      ((#\x) 10)
      		      ((#\l) 50)
      		      ((#\c) 100)
      		      ((#\d) 500)
      		      ((#\m) 1000))))
      	       (parse
      		(decf i)
      		(funcall 
      		(if (< y x) '- '+) x y))))))
          (parse (1- (length numeral)) 0)))

      Вполне в духе времени (почти как Linq)? если синтаксических ошибок нет, то будет работать :)
      Ответить
      • ЗЫ. Это я к тому, что в коде оригинала скобочек не хватает немного.

        (defun roman-to-arabic (numeral)
          (labels
              ((parse (i x)
        	 (if (< i 0) x
        	     (let ((y
        		    (ccase (aref numeral i)
        		      ((#\i) 1)
        		      ((#\v) 5)
        		      ((#\x) 10)
        		      ((#\l) 50)
        		      ((#\c) 100)
        		      ((#\d) 500)
        		      ((#\m) 1000))))
        	       (parse
        		(decf i)
        		(funcall 
        		(if (< (* y 4) x) '- '+) x y))))))
            (parse (1- (length numeral)) 0)))

        Упс, факир был пьян, вот теперь нормально.
        Ответить
        • Скобочки не нужны.
          Ответить
        • Немножко гк:

          (defun arabic (roman)
            (dotimes (num 4000)
              (when (and (not (zerop num))
          	       (string= (format nil "~@R" num) roman))
                (return num))))
          Ответить
          • А почему только до 4 тысяч? Из длины строки вполне можно расчитать максимальное число, которое можно из нее получить.
            Ответить
            • "При этом некоторые из цифр могут повторяться, но не желательно более трех раз, таким образом с их помощью можно записать любое целое число не более 3999 (MMMCMXCIX)" (wiki)
              об этом ещё упоминается в Dive Into Python

              Самый простой способ, на мой взгляд - воспользоваться format для составления таблицы соответствий и потом просто делать gethash
              Ответить
              • А, я не знал, что MMMM уже не катит. Ну тогда окей :)

                Тут фишка же в чем: интуитивно хочется составить LR(k) (в лучшем случае LR(1)) парсер. Но задача лучше решается через RL(k), особенно потому, что легко строится RL(1) парсер и с минимальными накладными расходами. Т.е. перефразируя, для того, чтобы работал LR парсер в lookahead нужно чтобы было 2 символа, а для RL достаточно одного.

                EDIT: А, хотя, мой вариант тоже бы не работал для MMMM, так что да.
                Ответить
                • Именно поэтому Мавроди ограничился только тремя М
                  Ответить
          • function arabicToRoman(input){
                var result;
                input = input.toLowerCase();
                function zero() { return 0; }
                function makeOrder(high, value){
            	return function(a){
            	    var r = value, p = zero, q = [];
            	    if (a){
            		p = a[0];
            		if (high.indexOf(p) > -1) r = -value;
            		q = [a.substr(1)];
            		if (p) p = this[p];
            	    }
            	    return value + p.apply(this, q);
            	}
                };
                var scope = {
            	i : makeOrder("vx", 1),
            	v : makeOrder("", 5),
            	x : makeOrder("cl", 10),
            	l : makeOrder("", 50),
            	c : makeOrder("md", 100),
            	d : makeOrder("", 500),
            	m : makeOrder("", 1000)
                };
                if (input)
            	result = scope[input[0]].apply(scope, [input.substr(1)]);
                return result;
            }


            Ну раз уж такое дело... можно сделать немного более функционально.
            Ответить
            • Или еще более функционально:
              arabicToRoman s = fst $ foldr step (0, 0) $ map roman s
                  where
                      roman 'M' = 1000
                      roman 'D' = 500
                      roman 'C' = 100
                      roman 'L' = 50
                      roman 'X' = 10
                      roman 'V' = 5
                      roman 'I' = 1
                      step x (sum, prev) | x >= prev = (sum+x, x)
                                         | otherwise = (sum-x, x)
              Ответить
              • Да не функциональней, чем sed, с другой стороны раз хаскель, то хотелось бы, например:

                *Main> romanToArabic "LC"
                Left (line 1, column 2):
                unexpected 'C'
                expecting "X", "IX", "IV", "V", "I" or end of input
                Ответить
    • echo "DCCCLXXXVIII" | sed 's/cm/900+/gi; s/m/1000+/gi;
      s/cd/400+/gi; s/d/500+/gi; s/xc/90+/gi; s/c/100+/gi;
      s/xl/40+/gi; s/l/50+/gi; s/ix/9+/gi; s/x/10+/gi;
      s/iv/4+/gi; s/v/5+/gi; s/i/1+/gi; s/$/0/;' | bc
      Ответить
      • Хотя, наверное, лучше так:

        echo "DCCCLXXXVIII" | sed `echo "cm900m1000cd400d500xc90c100xl40l50ix9x10iv4v5i1s/$/0/;" | sed -r 's/([a-z]+)([0-9]+)/s\/\1\/\2+\/gi;/g;'` | bc
        Ответить

    Добавить комментарий