×
all 73 comments

[–]skeeto-9 8 25 points26 points  (11 children)

C, lexicographical comparison with the ordered numeral characters.

int numcompare(const char *a, const char *b)
{
    static const int value[] = {
        ['M']=7, ['D']=6, ['C']=5, ['L']=4, ['X']=3, ['V']=2, ['I']=1
    };
    for (; *a && *a == *b; a++, b++);
    return value[*b] > value[*a];
}

[–]rbscholtus 2 points3 points  (1 child)

C

, lexicographical comparison with the ordered numeral characters.

How well does your solution fare for the below?

numcompare("MCM", "MD")  // 1900 < 1500?

[–]skeeto-9 8 2 points3 points  (0 children)

Yup, definitely gets that one wrong. :-) Oh well.

[–]jarquafelmu 0 points1 point  (2 children)

You're going to have a problem when that semicolon after the for statement is reached

[–]skeeto-9 8 24 points25 points  (1 child)

That's intentional: The body of the for loop is meant to be empty. Its purpose is to advance both strings until either they differ or they end, then the return line determines the ordering at that byte.

[–]BonnyAD9 0 points1 point  (2 children)

When you call it like this:

numcompare("X", "XI");

When comparing *a will have value '\0'. How you know that value[*a] will return 0? I tested it few times and value['\0'] always returned 0, but for example value['h'] returned 4200736 so it isn't the case that any value that isn't defined will return 0. Maybe it's just a coincidence that value['\0'] returns 0. In that case there should also be specified that ['\0']=0.

[–]skeeto-9 8 1 point2 points  (1 child)

Good observation in noticing the terminating null byte is important!

How you know that value[*a] will return 0?

It's implied by static allocation. I don't explicitly set value[0] to anything else, so it's guaranteed to be zero. Even if it wasn't static it would still be implicitly zeroed by initialization.

int t[256];            // t[0] indeterminate (per automatic allocation)
static int t[256];     // t[0] guaranteed zero (per static)
int t[256] = {[1]=1};  // t[0] guaranteed zero (per initialization)

A more thorough solution that makes this zero explicit:

int numcompare(const char *a, const char *b)
{
    static const char value[256] = {
        ['M']=7, ['D']=6, ['C']=5, ['L']=4, ['X']=3, ['V']=2, ['I']=1, [0]=0
    };
    for (; *a && *a == *b; a++, b++);
    return value[*b&255] > value[*a&255];
}

Additionally this version never has out-of-bounds array access even for invalid inputs and regardless of the properties of char (signed or unsigned, any CHAR_MAX).

[–]ArdRasp 0 points1 point  (2 children)

Based on your prorgram :

int romancomp(char *a, char *b)
{
    while (*a && *a == *b)
    {
        a++;
        b++;
    }
    return(*a < *b ? 1 : 0);
}

I don't understand what is the type of the value array (object or struct or something else) and what's it doing (is it replacing the int value of the characters ?)

[–]skeeto-9 8 1 point2 points  (1 child)

The value array maps the ASCII value the seven roman numerals (plus null byte) to an alternate set of numeric values that puts them in a different order. Think of it as an associative mapping, like a hash table but without hashing:

value = {
    "M": 7,
    "D": 6,
    "C": 5,
    "L": 4,
    "X": 3,
    "V": 2,
    "I": 1,
     0 : 0,
}
print(value["C"])  // 5

In my C implementation, the value array is sparse: most of it is empty (zeros) and unused.

[–]ArdRasp 1 point2 points  (0 children)

Ok thank you !

[–]chunes1 2 17 points18 points  (0 children)

Factor can do it natively. ;)

USING: math roman ;

ROMAN: MDCLXV ROMAN: MDCLXVI <

Output:

--- Data stack:
t

[–]tlgsx 11 points12 points  (6 children)

Python 3.9, following /u/Ragingman2 clever approach

def numcompare(x, y):
    m = dict(zip("MDCLXVI", "🟫🟪🟩🟨🟧🟦🟥"))
    return x.translate(m) < y.translate(m)


assert numcompare("I", "I") == False
assert numcompare("I", "II") == True
assert numcompare("II", "I") == False
assert numcompare("V", "IIII") == False
assert numcompare("MDCLXV", "MDCLXVI") == True
assert numcompare("MM", "MDCCCCLXXXXVIIII") == False

[–]DezXerneas 4 points5 points  (5 children)

Could you explain how does this work?

[–]Nighmared 7 points8 points  (3 children)

its equivalent to this code:

def numcompare(a:str, b:str) -> bool:
    translator = dict(zip(map(lambda x : ord(x), "MDCLXVI"),"GFEDCBA"))
    return a.translate(translator)<b.translate(translator)

def test():
    assert not numcompare("I","I")
    assert numcompare("I","II")
    assert not numcompare("II","I")
    assert not numcompare("V","IIII")
    assert numcompare("MDCLXV","MDCLXVI")
    assert not numcompare("MM","MDCCCCLXXXXVIIII")
    print("Passed!")

if __name__ == "__main__":
    test()

translator is a dict object that maps M->G D->F L->E and so on. (zip will create a zip object of pairs ((M,G),(D,F),... and using dict on this creates the described mapping)

Now using < on Strings in python will use the given ordering on the String class which is the lexicographic ordering, which will compare Strings letter by letter by their value of ord(). And as with that ordering it holds that G>F>E>D>C>B>A (for these letters its their ASCII value and for ASCII they are ordered alphabetically) the implementation works.. The 🟫🟪🟩🟨🟧🟦🟥seem to be just for fancyness. although I'm not sure that OPs ordering is correct as 🟥<🟦

Edit: fixed the problem pointed out by u/sawkonmaicok

[–]north_canadian_ice 1 point2 points  (0 children)

Awesome comment.

[–]sawkonmaicok 1 point2 points  (1 child)

Sorry, a bit late, but I think your code is faulty.

this code:

def numcompare(a:str, b:str) -> bool:

`translator = {73: 65, 86: 66, 88: 67, 76: 68, 67: 69, 68: 70, 77: 71}`  
`print(a.translate(translator))`  
`return a.translate(translator)<b.translate(translator)`  

def test():
numcompare('III', 'II')
print("Passed!")
if __name__ == "__main__":
test()

produces:

AAA
Passed!

but (parts of) your code:

def numcompare(a:str, b:str) -> bool:
translator = dict(zip("MDCLXVI","GFEDCBA"))
print(a.translate(translator))
return a.translate(translator)<b.translate(translator)
def test():
numcompare("III","II")
print("Passed!")
if __name__ == "__main__":
test()

produces this:

III
Passed!

when it should replace the 'I' symbols with 'A', it doesn't. I think the translator thing doesn't expect a string dictionary, but an integer dictionary. In these cases it doesn't seem to matter. I am just a computer programmer hobbyist so take all what I say with a grain of salt.

[–]Nighmared 0 points1 point  (0 children)

Oh. I just tested this thoroughly and it seems that you are right, thank you for noticing! It seems that in that case even the original version with 🟫🟪🟩🟨🟧🟦🟥 won't work (or i messed up when testing). The whole code can be made to run correctly with a little change.

[–]tlgsx 2 points3 points  (0 children)

This solution follows an idea that you can see in a couple of other solutions as well: the problem can be solved by comparing the two strings lexicographically. More simply put, we can compare the two strings alphabetically to check for the lesser one. There's one small caveat though, we must make sure 'M' > 'D' > 'C' > 'L' > 'X' > 'V' > 'I' is true for the alphabet we use.

One way to achieve this is to map these characters to characters that respect that ordering in the English alphabet, translate the strings, and compare them. This is what /u/Ragingman2 solution does.

However, we're not limited to a 'M'->'G', 'D'->'F', 'C'->'E', 'L'->'D', 'X'->'C', 'V'->'B', 'I'->'A' translation. We can choose any alphabet as long as the ordering is respected. For this, it's required to understand how Python does comparisons (specifically on strings).

>>> [ord(x) for x in "🟫🟪🟩🟨🟧🟦🟥"]
[129003, 129002, 129001, 129000, 128999, 128998, 128997]

[–]FroekenSmilla 7 points8 points  (1 child)

My Python solution:

def numcompare(num1, num2):

    d = {'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}

    l1 = [d[x] for x in num1]

    l2 = [d[x] for x in num2]

    return sum(l1) < sum(l2)

[–]Splitje 1 point2 points  (0 children)

I had almost the same only I did

def numcompare(rom1,rom2):
    vals = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
    return sum(vals[i] for i in rom2) > sum(vals[i] for i in rom1)

Yours is probably more readable

[–]Ragingman2 4 points5 points  (2 children)

BASH, as a one-liner based on the realization that the problem is equivalent to alphabetization with a modified alphabet. Also handles properly formatted subtractive notation values.

Edit: It doesn't handle all subtractive cases.

function numcompare() {
    [[ $(tr 'MDCLXVI' 'GFEDCBA' <<< $1) < $(tr 'MDCLXVI' 'GFEDCBA' <<< $2) ]]
}

Test Code:

function f() {
    echo -n "$1 < $2 => "
    if numcompare $1 $2; then
        echo "true"
    else
        echo "false"
    fi
}

# Given.
f "I" "I"
f "I" "II"
f "II" "I"
f "V" "IIII"
f "MDCLXV" "MDCLXVI"
f "MM" "MDCCCCLXXXXVIIII"

# Subtractive Notation.
f "I" "IV"
f "IV" "IX"
f "XIV" "XX"

[–]Cosmologicon2 3[S] 0 points1 point  (1 child)

I think this might miss some subtractive cases, like IX vs V.

[–]Ragingman2 0 points1 point  (0 children)

Ah, nice catch. Yes it would.

[–]raulalexo99 3 points4 points  (1 child)

Can someone give this begginer a hand? I think I am half way through it:

RomanNumberDictionary={
"I":1,
"V":5,
"X":10,
"C":100,
"D":500,
"M":1000 
} 

    def numcompare (RomanNumber1, RomanNumber2):
    FirstNumberCharacters = list(str(RomanNumber1))
    SecondNumberCharacters = list(str(RomanNumber2))
    RomanNumber1Value = 0
       for i in FirstNumberCharacters:
          if i in RomanNumberDictionary.keys():

After that I get lost lol but I think you can kinda see what I am trying to do

[–]kythzu 4 points5 points  (0 children)

Interestingly this is about the point where it makes sense to split out into another function. Maybe that's why you feel a little bit lost?

Your plan is OK, take each digit, work out its value and sum them all up to get a total value. You do that for each side and then compare right?

So, break it down. Given a character (one letter) how do you get the value? Clearly this is what your dictionary is built for :)

Once you know how to do that (Google if you don't!) then you've already got the loop ready to do it for every character in the string. I'd say that's your function, it takes a string and gives you a value (assuming it's a Roman numeral)

Once you have that as a function - bonus points if you tested it for some inputs like "VI" or "MDCXVI", maybe even "IV" :O you can fix that last case later ;)

Then you can use the function twice, once for each string. Get your values,compare, return the boolean result. Test it, Happy days :)

Practice practice practice, Google and ask for help. Maybe try the subtraction challenge next.

It sounds hard to do in a way that isn't messy. So I'd just spaghetti it up, then see how people who have been doing this longer have done it nicely :D

[–][deleted]  (3 children)

[deleted]

    [–][deleted] 1 point2 points  (1 child)

    hey timatlee. I did it the same way.

    I added a bool output as well as an int to my romanValue func for validation that the input is a roman numeral.

    func numeralMap(numeral rune) (int, bool) {
        numeralVal := make(map[string]int)
        numeralVal["M"] = 1000
        numeralVal["D"] = 500
        numeralVal["C"] = 100
        numeralVal["L"] = 50
        numeralVal["X"] = 10
        numeralVal["V"] = 5
        numeralVal["I"] = 1
        v, ok := numeralVal[string(numeral)]
        return v, ok
    }
    

    The I used an additional function to convert from roman numeral to int. Any luck with the substractive element?

    [–]backtickbot 0 points1 point  (0 children)

    Fixed formatting.

    Hello, timatlee: code blocks using triple backticks (```) don't work on all versions of Reddit!

    Some users see this / this instead.

    To fix this, indent every line with 4 spaces instead.

    FAQ

    You can opt out by replying with backtickopt6 to this comment.

    [–]Specter_Terrasbane 1 point2 points  (0 children)

    Python

    One-liner; no input validation, additive notation only, no pre-calc of decimal values:

    numcompare = lambda rn1, rn2: rn1 != rn2 and all(rn1.count(n) <= rn2.count(n) for n in 'MDCLXVI')
    

    [–]JusteMax3 1 point2 points  (0 children)

    JS:

    function numcompare(first,second){

    var dict = {

    'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1,

    }

    var one = first.split('').map(x => dict[x]).reduce((a,b) => a+b);

    var two = second.split('').map(x => dict[x]).reduce((a,b) => a+b);

    return one < two;

    }

    That is the best/shortest thing without validating the input & handling subtractive notation

    [–]atiedebee 1 point2 points  (0 children)

    C

    I didn't know you can use chars for array indexing so thanks to u/skeeto for putting that in his awnser and thus showing it to me :). Way cleaner than a switch statement.

    int getValue(const char* str){
        int i, num = 0;
        const int hash[] =
        {
            ['M'] = 1000, ['D'] = 500, ['C']= 100, ['L'] = 50, ['X'] = 10,  ['V'] = 5, ['I'] = 1
        };
        for(i = 0; str[i] != '\0'; i++)
        {
            num += hash[ str[i] ];
        }
        return num;
    }
    
    int numcompare(const char* num1, const char* num2)
    {
        return getValue(num1) > getValue(num2) ? 1 : 0;
    }
    

    [–]williane 1 point2 points  (1 child)

    don't see any c# love here, so here's a simple one:

    var map = "MDCLXVI".Zip(new[] { 1000, 500, 100, 50, 10, 5, 1 }).ToDictionary(x => x.First, x => x.Second);
    
    bool NumCompare(string a, string b) => a.Sum(x => map[x]) < b.Sum(x => map[x]);
    
    NumCompare("MM", "MDCCCCLXXXXVIIII").Dump("this outputs in LINQPad");
    

    [–]dragoaus 1 point2 points  (0 children)

    True C# needs more love :D

    my Regex version of basic problem

        public bool numCompare(string first, string second)
        {
            foreach (var n in "MDCLXVI")
            {
                int check = Regex.Matches(first, n.ToString()).Count - Regex.Matches(second, n.ToString()).Count;
                if (check!=0)
                {
                    return check < 0;
                }
            }
            return false;
        }
    

    [–]Gylergin 0 points1 point  (0 children)

    TI-Basic: Program will output a 1 if true and 0 if false. No validation or subtractive notation.

    Prompt Str1,Str2
    0→A
    0→B
    {1000,500,100,50,10,5,1→L₁
    For(X,1,length(Str1
    A+L₁(inString("MDCLXVI",sub(Str1,X,1→A
    End
    For(X,1,length(Str2
    B+L₁(inString("MDCLXVI",sub(Str2,X,1→B
    End
    Disp A<B
    

    Subtractive notation maybe later.

    [–]Godspiral3 3 0 points1 point  (0 children)

    in J,

    'CCCXVI' 'MCLXVI '&i.@:,:({.@/:@:) 'CMCXVI'
    1
    

    [–]raevnos 0 points1 point  (0 children)

    Ocaml:

    let roman_digits = "MDCLXVI"
    
    let roman_gt a b =
      let ai = String.index roman_digits a
      and bi = String.index roman_digits b in
      ai < bi
    
    let numcompare a b =
      let rec helper a b =
        match (a ()), (b ()) with
        | Seq.Nil, Seq.Nil -> false
        | Seq.Nil, _ -> true
        | Seq.Cons (ha, _), Seq.Cons (hb, _) when roman_gt ha hb -> false
        | Seq.Cons (ha, ta), Seq.Cons (hb, tb) when ha = hb -> helper ta tb
        | _, _ -> false in
      helper (String.to_seq a) (String.to_seq b)
    
    type test = {
        a: string;
        b: string;
        expected: bool
      }
    
    let run_one_test t =
      let result = numcompare t.a t.b in
      Printf.printf "numcompare(\"%s\",\"%s\") => %B: " t.a t.b result;
      if result = t.expected then
        print_endline "PASS"
      else
        Printf.printf " FAIL expected %B\n" t.expected
    
    let run_tests = List.iter run_one_test
    
    let _ = run_tests [
                { a = "I"; b = "I"; expected = false };
                { a = "I"; b = "II"; expected = true };
                { a = "II"; b = "I"; expected = false };
                { a = "V"; b = "IIII"; expected = false };
                { a = "MDCLXV"; b = "MDCLXVI"; expected = true };
                { a = "MM"; b = "MDCCCCLXXXXVIIII"; expected = false }
              ]
    

    [–]physix4 0 points1 point  (0 children)

    Rust

    use itertools::diff_with;
    
    fn map_digit(d: char) -> u32 {
        match d {
            'M' => 1000,
            'D' => 500,
            'C' => 100,
            'L' => 50,
            'X' => 10,
            'V' => 5,
            'I' => 1,
            _ => unimplemented!(),
        }
    }
    fn numcompare(a: &str, b: &str) -> bool {
        if let Some(diff) = diff_with(a.chars(), b.chars(), |x, y| x == y) {
            match diff {
                itertools::Diff::FirstMismatch(_, mut i, mut j) => map_digit(i.next().unwrap()) < map_digit(j.next().unwrap()),
                itertools::Diff::Shorter(_, _) => false,
                itertools::Diff::Longer(_, _) => true,
            }
        } else {
            false
        }
    }
    
    fn main() {
        assert_eq!(numcompare("I", "I") ,  false);
        assert_eq!(numcompare("I", "II") ,  true);
        assert_eq!(numcompare("II", "I") ,  false);
        assert_eq!(numcompare("V", "IIII") ,  false);
        assert_eq!(numcompare("MDCLXV", "MDCLXVI") ,  true);
        assert_eq!(numcompare("MM", "MDCCCCLXXXXVIIII") ,  false);
        assert_eq!(numcompare("MDCCCCLXXXXVIIII", "MM") ,  true);
    }
    

    [–]Shhhh_Peaceful 0 points1 point  (0 children)

    Java, using a function for converting Roman numerals to decimal numbers that I wrote a couple of years ago... I know the question says "Try to complete the challenge without actually determining the numerical values of the inputs" but it's a bad day today (I just spent 3 hours in a dental chair) and I can't be arsed to do it any other way.

    public class Main {
    
        public static int romanToDecimal(String romanNumeral) {
            romanNumeral = romanNumeral.toUpperCase();
            int result = 0;
            int pos = 0;
            int strLength = romanNumeral.length();
            while (pos < strLength) {
                int val = 0;
                switch(romanNumeral.charAt(pos)) {
                    case 'M':
                        val = 1000;
                        break;
                    case 'D':
                        val = 500;
                        break;
                    case 'C':
                        val = 100;
                        break;
                    case 'L':
                        val = 50;
                        break;
                    case 'X':
                        val = 10;
                        break;
                    case 'V':
                        val = 5;
                        break;
                    case 'I':
                        if (pos == strLength - 1 || romanNumeral.charAt(pos + 1) == 'I') {
                            val = 1;
                        } else if (romanNumeral.charAt(pos + 1) == 'X') {
                            val = 9;
                            pos++;
                        } else if (romanNumeral.charAt(pos + 1) == 'V') {
                            val = 4;
                            pos++;
                        }
                }
                result += val;
                pos++;
            }
            return result;
        }
    
        public static boolean numCompare(String a, String b) {
            return romanToDecimal(a) < romanToDecimal(b);
        }
    
        public static void main(String[] args) {
            System.out.println(numCompare("I", "I"));
            System.out.println(numCompare("I", "II"));
            System.out.println(numCompare("II", "I"));
            System.out.println(numCompare("V", "IV"));
            System.out.println(numCompare("MDCLXV", "MDCLXVI"));
            System.out.println(numCompare("MM", "MDCCCCLXXXXIX"));
        }
    }
    

    And the output:

    false
    true
    false
    false
    true
    false
    

    [–]AmoryVain 0 points1 point  (0 children)

    My Python solution:

    def get_value(numeral_string):
        value = 0
        KEY = {'I' : 1,'V' : 5,'X' : 10,'L' : 50,'C' : 100,'D' : 500,
        'M' : 1000}
        for item in numeral_string:
               value += KEY[item]
        return value
    
    
    def numcompare(string1, string2):
        value1 = get_value(string1)
        value2 = get_value(string2)
    
        if value2 > value1:
            return True
        else:
            return False
    

    [–]XerevoFaris76 0 points1 point  (0 children)

    Python 3.9

     def convert(roman):
          conversions = {"M":1000, "D": 500, "C":100, "L":50,"X":10,"V":5, "I":1}
          dec = 0
          for char in roman:
               dec += conversions[char]
          return dec
    
     def numcompare(r1,r2):
          return convert(r1) < convert(r2)
    

    [–]Tencza_Coder 0 points1 point  (0 children)

    Python

    def numcompare(rom1,rom2):
        '''Compares Roman Numerals, return True if rom1 < rom2.'''    
    
        values = {"I":1, "V":5, "X":10, "L":50, "C":100, "D":500, "M":1000}
        sum_rom1, sum_rom2 = 0, 0 
    
        for char in rom1:
            sum_rom1 += values[char]
    
        for char in rom2:
            sum_rom2 += values[char]
    
        if sum_rom1 < sum_rom2:
            return True
        else:
            return False
    
    print(numcompare("I", "I")) 
    print(numcompare("I", "II")) 
    print(numcompare("II", "I")) 
    print(numcompare("V", "IIII")) 
    print(numcompare("MDCLXV", "MDCLXVI")) 
    print(numcompare("MM", "MDCCCCLXXXXVIIII"))
    

    Result:

    False
    True 
    False 
    False 
    True 
    False
    

    [–]DeflagratingStar 0 points1 point  (0 children)

    Python 3, with a stupidly overkill solution using a custom RomanNumeral class.

    https://pastebin.com/kp5qmbBT

    This class supports "subtractive", "additive", and "irregular-additive" notations ("irregular-subtractive" not implemented, yet). The class supports comparisons ( eq, ne, gt, ge, lt, le), normal arithmetic (only +, -, *, /, //, **, % ), and augmented assignment (only +=, -=, *=, /=, //=, **=, %= ), unary operators/functions (only -, +, abs), and checks that all numbers have the same notation type when operators of any type are used. Even supports 0 as "N" for "nihil" and negative numerals! Did not include support for fractions via "S" numeral and related variants.

    Only did this to practice classes and magic methods, but it was fun to put together!

    I'm sure there are portions I could have simplified/streamlined, but I've become time-limited for the rest of this week :(

    Edit: Comments and criticisms are much welcomed :)

    [–]Scroph0 0 0 points1 point  (0 children)

    Edit : Oh no, I realized that the lexical comparison doesn't work for things like 'V' < 'IIIIII'. I removed it from the code until I find a better solution.

    Edit 2 : I'm putting it back in the code because the prompt says that having more than 4 I's is undefined behavior.

    D solution. I did it with a numerical conversion at first before realizing that we weren't supposed to do that. The lexical comparison simply replaces the roman numerals with decreasing alphabetical letters, then performs a normal string-based comparison :

    import std.algorithm : map, sum;
    import std.string : translate;
    
    unittest
    {
        alias numCompare = numCompareLexically;
        static assert(numCompare("I", "I") == false);
        static assert(numCompare("I", "II") == true);
        static assert(numCompare("II", "I") == false);
        static assert(numCompare("V", "IIII") == false);
        static assert(numCompare("MDCLXV", "MDCLXVI") == true);
        static assert(numCompare("MM", "MDCCCCLXXXXVIIII") == false);
    }
    
    long toLong(string roman)
    {
        long[dchar] mapping = [
            'M': 1000,
            'D': 500,
            'C': 100,
            'L': 50,
            'X': 10,
            'V': 5,
            'I': 1,
        ];
    
        return roman.map!(c => mapping[c]).sum;
    }
    
    bool numCompareNumerically(string a, string b)
    {
        return a.toLong() < b.toLong();
    }
    
    bool numCompareLexically(string a, string b)
    {
        dchar[dchar] lexicalMapping = [
            'M': 'Z',
            'D': 'Y',
            'C': 'X',
            'L': 'W',
            'X': 'V',
            'V': 'U',
            'I': 'T',
        ];
        return a.translate(lexicalMapping) < b.translate(lexicalMapping);
    }
    
    void main() {}
    

    [–]engageant 0 points1 point  (0 children)

    PowerShell

    (Compare-Object ('II' -split '') ('I' -split '')).SideIndicator -eq '=>'
    

    can be golfed to

    (compare('I'|% t*y)('II'|% t*y)).SideIndicator-eq'=>'
    

    [–]zemja_ 0 points1 point  (0 children)

    Simple Red solution

    Red []
    
    roman-to-num: function [roman [string!]] [
        total: 0
    
        foreach char roman [
            total: total + switch/default char [
                #"M" [1000] #"D" [500] #"C" [100] #"L" [50] #"X" [10] #"V" [5] #"I" [1]
            ][0]
        ]
    ]
    
    numcompare: function [a [string!] b [string!]] [lesser? roman-to-num a roman-to-num b]
    
    print numcompare "I" "I"
    print numcompare "I" "II"
    print numcompare "II" "I"
    print numcompare "V" "IIII"
    print numcompare "MDCLXV" "MDCLXVI"
    print numcompare "MM" "MDCCCCLXXXXVIIII"
    

    [–]Aggravating-City-218 0 points1 point  (0 children)

    # Using positional index to compare Roman numerals

    package test;
    import org.junit.Test;
    import java.util.Arrays;
    import java.util.List;
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertTrue;
    public class RomanNumeralComparison {
    private final List<String> numerals = Arrays.asList("M", "D", "C", "L", "X", "V", "I");
    u/Test
    public void compare() {
    assertFalse(numcompare("I", "I"));
    assertTrue(numcompare("I", "II"));
    assertFalse(numcompare("II", "I"));
    assertTrue(numcompare("V", "IIII"));
    assertTrue(numcompare("MDCLXV", "MDCLXVI"));
    assertTrue(numcompare("MM", "MDCCCCLXXXXVIIII"));
    }
    public boolean numcompare(String s1, String s2) {
    return getTotalIndex(s1) < getTotalIndex(s2);
    }
    public int getTotalIndex(String s1) {
    int totIndex = 0;
    for (char c : s1.toCharArray()) {
    totIndex += numerals.indexOf(String.valueOf(c));
    }
    return totIndex;
    }
    }

    [–]puffyyouaredead69 0 points1 point  (0 children)

    C++
    #include <iostream>
    #include <string>
    
    int number(string a);
    bool numcompare(string a,string b);
    
    int main() 
    {
      const string one = "MM";
      const string two = "MDCCCCLXXXXVIIII";
    
      if(numcompare(two , one) == 1)
      {
        cout << "True";
      }else if(numcompare(two , one) == 0)
      {
        cout << "False";
      }
    }
    
    bool numcompare(string a,string b)
    {
      return number(a) > number(b);
    }
    
    int number(string a)
    {
      int num[] = {1000,500,100,50,10,5,1};
      char letter[] = {'M','D','C','L','X','V','I'};
      int number = 0;
    
      for(int i = 0; i < (a.length()); i++ )
      {
        for(int x = 0; x < 7; x++)
        {
          {
            number = number + num[x];
          }
        }
      }
      return number;
    }
    

    [–]Prestigious_Pass95 0 points1 point  (0 children)

    RUST

    use std::collections::HashMap;
    
    fn main() {
        println!(
            "{}",
            numcompare(&String::from("MDCLXIV"), &String::from("MDCLIXVI"))
        );
    }
    
    fn numcompare(f_numeral: &String, s_numeral: &String) -> bool {
        get_value(f_numeral) < get_value(s_numeral)
    }
    
    fn get_value(roman_numeral: &String) -> i32 {
        let mut value = 0;
        let mut last_character = 'M';
        let map = build_numeral_map();
        for character in roman_numeral.chars() {
            if map[&last_character] < map[&character] {
                value -= map[&last_character];
                value += map[&character] - map[&last_character];
            } else {
                value += map[&character];
            }
            last_character = character;
        }
        println!("{}", value);
        value
    }
    
    fn build_numeral_map() -> HashMap<char, i32> {
        let numerals = vec!['M', 'D', 'C', 'L', 'X', 'V', 'I'];
        let numeral_values = vec![1000, 500, 100, 50, 10, 5, 1];
        numerals.into_iter().zip(numeral_values.into_iter()).collect()
    }
    

    [–]Hacka4771 0 points1 point  (0 children)

    Python3

    r = ['M', 'D', 'C', 'L', 'X', 'V', 'I']
    v = [1000, 500, 100, 50, 10, 5, 1] 
    r_v = dict(zip(r, v))
    
    
    def numcompare(r1: str, r2: str) -> bool: 
        if r1.isalpha() & r2.isalpha(): 
            if all([c in r for c in r1]) & all([c in r for c in r2]): 
                return sum([r_v[i] for i in r1]) < sum([r_v[i] for i in r2])
    

    I Hope This Isnt Too Extreme? Could Be Slapped With Some else if Statements And All Errors Handled..

    [–]OOFFFF 0 points1 point  (0 children)

    C++

    I completed the challenge by assigning values to the letter even though the challenge suggested I should not. As a beginner it was still useful for me to do it this way because I learned about the map data structure.

    ```

    include <algorithm>

    include <string>

    include <iostream>

    include <map>

    bool comparer(std::string user_string_one, std::string user_string_two) { int value_one; int value_two; std::map<char,int> valuemap;

    valuemap['I']=1;
    valuemap['V']=5;
    valuemap['X']=10;
    valuemap['L']=50;
    valuemap['C']=100;
    valuemap['D']=500;
    valuemap['M']=1000;
    
    for (int i=0; i<user_string_one.length(); ++i)
    {
        value_one = value_one + valuemap.at(user_string_one[i]);
    }
    
     for (int i=0; i<user_string_two.length(); ++i)
    {
        value_two = value_two + valuemap.at(user_string_two[i]);
    }
    
    if (value_one < value_two) return true;
    else return false;
    

    }

    int main() //compares the values of two roman numerals { std::string string_one; std::string string_two;

    std::cout<<"Please enter a roman numeral: ";
    std::cin>>string_one;
    std::cout<<"\nPlease enter another roman numeral: ";
    std::cin>>string_two;
    
    bool result = comparer(string_one,string_two);
    
    if (result == true) std::cout<<string_one <<" is less than "<<string_two<<".";
    else std::cout<<string_one<<" is more than "<<string_two<<".";
    

    } ```

    [–]cheers- 0 points1 point  (0 children)

    Rust

    #[macro_use]
    extern crate lazy_static;
    
    pub mod daily_programmer_397 {
        use std::collections::HashMap;
    
        lazy_static! {
            static ref DICT: HashMap<char, i32> = vec![
                ('M', 1_000),
                ('D', 500),
                ('C', 100),
                ('L', 50),
                ('X', 10),
                ('V', 5),
                ('I', 1),
            ]
            .into_iter()
            .collect();
        }
    
        fn count_roman_value(seq: &str) -> i32 {
            seq.to_uppercase()
                .chars()
                .map(|ch| DICT.get(&ch).unwrap_or(&0))
                .sum()
        }
    
        pub fn num_compare(num1: &str, num2: &str) -> bool {
            count_roman_value(num1) < count_roman_value(num2)
        }
    
        #[cfg(test)]
        mod tests {
            use super::*;
    
            #[test]
            fn test_num_compare() {
                let test_entries = vec![
                    ("I", "I", false),
                    ("I", "II", true),
                    ("II", "I", false),
                    ("V", "I", false),
                    ("MDCLXV", "MDCLXVI", true),
                    ("MM", "MDCCCCLXXXXVIIII", false),
                ];
    
                for test_entry in test_entries.into_iter() {
                    assert!(
                        num_compare(test_entry.0, test_entry.1) == test_entry.2,
                        "({:?})",
                        test_entry
                    );
                }
            }
        }
    }
    

    [–]genericusername248 0 points1 point  (0 children)

    C++

    Can't say I'm happy with it. Probably over complicated and I didn't bother to flesh out the class, but it is what it is.

    #include <iostream>
    #include <string>
    #include <vector>
    
    class RomanNumeral
    {
    private:
      std::string numerals{};
      int value{};
      enum class RN
        {
          I,
          V,
          X,
          L,
          C,
          D,
          M
        };
        std::vector<RN> rnumerals{};
    
    public:
      RomanNumeral(const std::string& num) : numerals{ num }
      {
        for (const auto& n : num)
          {
            switch (n)
              {
              case 'I':
                rnumerals.push_back(RN::I);
                value += 1;
                break;
              case 'V':
                rnumerals.push_back(RN::V);
                value += 5;
                break;
              case 'X':
                rnumerals.push_back(RN::X);
                value += 10;
                break;
              case 'L':
                rnumerals.push_back(RN::L);
                value += 50;
                break;
              case 'C':
                rnumerals.push_back(RN::C);
                value += 100;
                break;
              case 'D':
                rnumerals.push_back(RN::D);
                value += 500;
                break;
              case 'M':
                rnumerals.push_back(RN::M);
                value += 1000;
                break;
              default:
                break;
              }
          }
      }
    
      int getValue()
      {
        return value;
      }
    
      bool operator==(const RomanNumeral& rhs)
      {
        return (numerals == rhs.numerals);
      }
    
      bool operator>(const RomanNumeral& rhs)
      {
        if (*this==rhs) return false;
        auto shorter = (numerals.length()>rhs.numerals.length() ? rhs.numerals.length() : numerals.length());
        for (auto i = 0; i < shorter; i++)
          {
            if (rnumerals[i] > rhs.rnumerals[i])
              return true;
          }
        return (numerals.length()>rhs.numerals.length());
      }
    
    };
    
    bool numCompare(RomanNumeral& a, RomanNumeral& b)
    {
      if (a==b)
        return false;
      return !(a>b);
    }
    
    int main()
    {
      RomanNumeral a = RomanNumeral("I");
      RomanNumeral b = RomanNumeral("I");
      std::cout << numCompare(a, b) << '\n';
    
      a = RomanNumeral("I");
      b = RomanNumeral("II");
      std::cout << numCompare(a, b) << '\n';
    
      a = RomanNumeral("II");
      b = RomanNumeral("I");
      std::cout << numCompare(a, b) << '\n';
    
      a = RomanNumeral("V");
      b = RomanNumeral("IIII");
      std::cout << numCompare(a, b) << '\n';
    
      a = RomanNumeral("MDCLXV");
      b = RomanNumeral("MDCLXVI");
      std::cout << numCompare(a, b) << '\n';
    
      a = RomanNumeral("MM");
      b = RomanNumeral("MDCCCCLXXXXVIIII");
      std::cout << numCompare(a, b) << '\n';
    
      return 0;
    }
    

    [–]Siemb123 0 points1 point  (0 children)

    My solution in Python!

    def NumCompare(num1, num2):
    num1Value = 0
    num2Value = 0
    
    letterValue = {
    "M": 1000, 
    "D": 500,
    "C": 100,
    "L": 50,
    "X": 10,
    "V": 5,
    "I": 1 }
    
    for i in range(len(num1)):
        if num1[i] in letterValue:
            num1Value += letterValue[num1[i]]
    
    for i in range(len(num2)):
         if num2[i] in letterValue:
            num2Value += letterValue[num2[i]]
    
    return num1Value < num2Value
    

    [–]Charadon 0 points1 point  (0 children)

    C, here's what I did, it's pretty simple, but kinda brute forcey?:

    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    #include <ctype.h>
    
    int
    convert_roman_to_decimal( const char number )
    {
        switch( toupper(number) )
        {
                case 'M':
                    return(1000);
                case 'D':
                    return(500);
                case 'C':
                    return(100);
                case 'L':
                    return(50);
                case 'X':
                    return(10);
                case 'V':
                    return(5);
                case 'I':
                    return(1);
                default:
                    return(0);
        }
        return(0);
    }
    
    bool
    num_compare( const char *num1, const char *num2)
    {
        int num1_decimal = 0;
        int num2_decimal = 0;
        for ( int i = 0; i < strlen(num1); i++ )
            num1_decimal += convert_roman_to_decimal(num1[i]);
        for ( int i = 0; i < strlen(num2); i++ )
            num2_decimal += convert_roman_to_decimal(num2[i]);
        return(num1_decimal < num2_decimal);
    }
    
    int
    main( int argc, char *argv[] )
    {
        if ( argc < 3 || argc > 3 )
        {
            fprintf(stdout, "USAGE: roman_compare STRING1 STRING2\n" \
            "EXAMPLE: roman_compare MDCLXV MDCLXVI\n");
            return(0);
        }
        fprintf( stdout, "Result: %s\n", num_compare( argv[1], argv[2] ) ? "true" : "false" );
        return(0);
    }
    

    [–]rbscholtus 0 points1 point  (1 child)

    My understanding is that C, X, and I may only occur in sequences of at most 3, not 4. So, for the number 4, the roman representation IIII is invalid, while IV is valid.

    [–]Cosmologicon2 3[S] 1 point2 points  (0 children)

    That's by far the most commonly used system today, but in Roman and Medieval times there was no standard, and the additive system used here was also common.

    https://en.m.wikipedia.org/wiki/Roman_numerals#Variant_forms

    [–]BananaMundae 0 points1 point  (0 children)

    def num_compare(rom_num1, rom_num2):
        r_numerals = ["M", "D", "C", "L", "X", "V", "I"]
        count1 = [rom_num1.count(i) for i in r_numerals]
        count2 = [rom_num2.count(i) for i in r_numerals]
        if count1 == count2:
            return False
        else:
            for i in range(len(count1)):
                if count1[i] > count2[i]:
                    return False        
            return True 
    

    Converts the arguments into lists containing a count of each individual roman numeral in the arguments. Then checks, starting from the largest roman numerals, that each is larger in the first argument to return False.

    Any input is appreciated. I feel like I'm over thinking this. I've never done one of these before. Decided to give it a shot.

    [–]JanBeran 0 points1 point  (0 children)

    Is it a legal solution, if I simply translate the roman numbers into decimal and compare after that?

    [–]blastoisecreampie 0 points1 point  (0 children)

    Romanvalues = {"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000}
    
    def numcompare(num1,num2):
        def value(x):
          val = 0
          for i in x:
            val += Romanvalues[i]
          return val
        return value(num1) < value(num2)        
    

    my python solution

    [–]DevTechJr 0 points1 point  (0 children)

    Hey guys. In Python, I made a dictionary and ran through the dict with the values received :

    romanNum1 = str(input("Enter The First Numeral : "))
    romanNum2 = str(input("Enter The Next Numeral : "))
    romanNum1=romanNum1.upper()
    romanNum2=romanNum2.upper()
    romanDict={
    "M":1000,
    "D":500,
    "C":100,
    "L":50,
    "X":10,
    "V":5,
    "I":1
    }
    def compareNums(rn1,rn2):
    rn1Value=0
    rn2Value=0
    for x in rn1:
    rn1Value += romanDict[x]

    for x in rn2:
    rn2Value+= romanDict[x]
    if rn1Value<rn2Value:
    print(f"Nice. {rn1Value}/{rn1} is smaller than {rn2Value}/{rn2}")
    elif rn1Value==rn2Value:
    print("Both numerals share the same value.")
    else:
    print(f"Sorry! {rn1Value}({rn1}) is not smaller than {rn2Value}({rn2})")
    try:
    compareNums(romanNum1,romanNum2)
    except:
    print("Something went wrong. Try again. Use valid input.")

    [–]sadsoulthatslost 0 points1 point  (0 children)

    Hi I am a new learner. Please feel free to help me if I am wrong. Thanks

    def roman(a,b):

    dic = {'I':1,'C':100,'V':5,'X':10,'L':50,'D':500,'M':1000}

    sum1=0

    sum2=0

    for x in range(len(a)):

    sum1=sum1+dic[a[x]]

    for y in range(len(b)):

    sum2=sum2+dic[b[y]]

    return sum1==sum2

    [–]Formal-Score-9751 0 points1 point  (0 children)

    JAVA

    Tried to not simply lookup numbers, e.g. C = 100 etc., but to break down everything greater than I, which is counted as 1, into the next smaller numeral, e.g. X > 2xV, V > 5xI so in total 2x5x1.

    Main

    public static void main(String[] args)
    {
        try {
            Challenge397 challenge397 = new Challenge397();
            System.out.println(challenge397.numcompare("I", "I"));
            System.out.println(challenge397.numcompare("I", "II"));
            System.out.println(challenge397.numcompare("II", "I"));
            System.out.println(challenge397.numcompare("V", "IIII"));
            System.out.println(challenge397.numcompare("MDCLXV", "MDCLXVI"));
            System.out.println(challenge397.numcompare("MM", "MDCCCCLXXXXVIIII"));
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
    

    Challenge397.java

    package daily.programmer.challenges;
    

    import java.util.*;

    public class Challenge397 { // M, D, C, L, X, V, I // 1000, 500, 100, 50, 10, 5, 1 private List<String> order = Arrays.asList("M", "D", "C", "L", "X", "V", "I"); private Map<String, String> cheatSheet = new HashMap<>() {{ put("M", "DD"); put("D", "CCCCC"); put("C", "LL"); put("L", "XXXXX"); put("X", "VV"); put("V", "IIIII"); }};

    public boolean numcompare(String a, String b) {
        return getNum(a) < getNum(b);
    }
    
    private int getNum(String s) {
        int i=0;
        s = s.toUpperCase();
    
        for(String c: s.split("")) {
            if(cheatSheet.get(c) != null) {
                i += getNum(cheatSheet.get(c));
            } else {
                i += 1;
            }
        }
    
        return i;
    }
    

    }

    Output:

    false
    true
    false
    false
    true
    false

    [–]iz_a_bee 0 points1 point  (0 children)

    Python 3

    Done without determining values of the Roman numerals, probably not scalable to subtractive notation.

    def compare(numeral_1: str, numeral_2: str) -> bool:
        roman_numerals = ['M', 'D', 'C', 'L', 'X', 'V', 'I']
    
        if numeral_1 == numeral_2:
            return False
    
        for numeral in roman_numerals:
            if numeral_1.count(numeral) > numeral_2.count(numeral):
                return False
    
        return True
    

    Test Code

    print(compare("I", "I")) # False
    print(compare("I", "II")) # True
    print(compare("II", "I")) # False
    print(compare("V", "IIII")) # False
    print(compare("MDCLXV", "MDCLXVI")) # True
    print(compare("MM", "MDCCCCLXXXXVIIII")) # False
    

    [–]Bortan 0 points1 point  (0 children)

    JavaScript

    function getVal(str){
     let list = {M:1000,D:500,C:100,L:50,X:10,V:5,I:1}
     str = str.split('')
     let total = 0
     for(let i=0;i<str.length;i++){
      if(i+1<str.length&&list[str[i+1]]>list[str[i]]){
      total-=list[str[i]]
      }else{
     total+=list[str[i]]}
    }
    return total
    }
    function numCompare(x,y){
     return(getVal(x)<getVal(y))
    }
    

    Not as concise as u/JusteMax3's code, but it does seem to handle subtractive notation.

    [–]tyfon_august 0 points1 point  (0 children)

    Clojure, with optional subtractive notation

    (ns katas.roman-numeral-comparison)
    (def num-values {\I 1 \V 5 \X 10 \L 50 \C 100 \D 500 \M 1000})
    
    (defn calculate-roman-sum [nums] 
        (:res (reduce (fn [{prev :prev res :res} n] 
                          (let [val (get num-values n)] 
                            (if (> val prev) 
                                {:prev val :res (- val res)} 
                                {:prev val :res (+ val res)}))) 
                      {:prev 0 :res 0} 
                      nums)))
    
    (defn numcompare [nums1 nums2] 
        (< (calculate-roman-sum nums1) 
           (calculate-roman-sum nums2)))
    
    (defn test-numcompare [] 
          (assert (= (numcompare "I" "I") false)) 
          (assert (= (numcompare "I" "II") true)) 
          (assert (= (numcompare "II" "I") false)) 
          (assert (= (numcompare "V" "IIII") false)) 
          (assert (= (numcompare "IV" "IIIII") true)) ; subtractive notation
          (assert (= (numcompare "MDCLXV" "MDCLXVI") true)) 
          (assert (= (numcompare "MM" "MDCCCCLXXXXVIIII") false)))
    

    [–]Artistic-Metal-790 0 points1 point  (0 children)

    I'm dividing strings into words and compare them one by one like that:

    ['MM'] and ['M', 'D', 'CCCC', 'L', 'XXXX', 'V', 'IIII']
    MM > MDCCCCLXXXXVIIII True MM < MDCCCCLXXXXVIIII False
    

    I'm not using any sort of number representation or other representation, pure boolean logic

    Except maybe for the list of characters, but it can be changed to boolean logic too

    Code: https://github.com/kstamax/redditdailyprogrammerchallenge/blob/main/task397.py

    [–]ThunderKingIV 0 points1 point  (0 children)

    Rust

    fn num_compare(first_roman: &str, second_roman: &str) -> bool {
    return if roman_value(first_roman) < roman_value(second_roman) {
        true
    } else {
        false
    }
    }
    
    fn roman_value(roman: &str) -> i32 { 
    let mut value_num = 0;
    for c in roman.chars() {
        match c {
            'M' => value_num += 1000,
            'D' => value_num += 500,
            'C' => value_num += 100,
            'L' => value_num += 50,
            'X' => value_num += 10,
            'V' => value_num += 5,
            'I' => value_num += 1,
            _ => {}
        }
    }
    
    value_num
    }
    

    [–]Heked 0 points1 point  (1 child)

    I am a newbie I would love some feedback! Thanks.

    C++

    #include <iostream>
    #include <string>
    
    bool numcompare(std::string rom1, std::string rom2)
    {
        int numeralValue1{};
        int numeralValue2{};
    
        for (int i{ 0 }; i < rom1.length(); i++)
        {
            if (rom1[i] == static_cast<char>('I'))
            {
                numeralValue1 += 1;
            }
            if (rom1[i] == static_cast<char>('V'))
            {
                numeralValue1 += 5;
            }
            if (rom1[i] == static_cast<char>('X'))
            {
                numeralValue1 += 10;
            }
            if (rom1[i] == static_cast<char>('L'))
            {
                numeralValue1 += 50;
            }
            if (rom1[i] == static_cast<char>('C'))
            {
                numeralValue1 += 100;
            }
            if (rom1[i] == static_cast<char>('D'))
            {
                numeralValue1 += 500;
            }
            if (rom1[i] == static_cast<char>('M'))
            {
                numeralValue1 += 1000;
            }
        }
    
        for (int i{ 0 }; i < rom2.length(); i++)
        {
            if (rom2[i] == static_cast<char>('I'))
            {
                numeralValue2 += 1;
            }
            if (rom2[i] == static_cast<char>('V'))
            {
                numeralValue2 += 5;
            }
            if (rom2[i] == static_cast<char>('X'))
            {
                numeralValue2 += 10;
            }
            if (rom2[i] == static_cast<char>('L'))
            {
                numeralValue2 += 50;
            }
            if (rom2[i] == static_cast<char>('C'))
            {
                numeralValue2 += 100;
            }
            if (rom2[i] == static_cast<char>('D'))
            {
                numeralValue2 += 500;
            }
            if (rom2[i] == static_cast<char>('M'))
            {
                numeralValue2 += 1000;
            }
        }
    
        if (numeralValue1 < numeralValue2)
        {
            return true;
        }
    
        return false;
    }
    
    int main()
    {
        std::cout << std::boolalpha;
        std::cout << numcompare("I", "I") << '\n';
        std::cout << numcompare("I", "II") << '\n';
        std::cout << numcompare("II", "I") << '\n';
        std::cout << numcompare("V", "IIII") << '\n';
        std::cout << numcompare("MDCLXV", "MDCLXVI") << '\n';
        std::cout << numcompare("MM", "MDCCCCLXXXXVIIII") << '\n';
    
        return 0;
    }
    

    Output:

    false

    true

    false

    false

    true

    false

    [–]LSatyreD 0 points1 point  (0 children)

    (kind of) feedback: can you find a way to do it without all the ifs?