2

In my table I have this field:

public string CARD_MANA_CONVT { get; set; }

It is a numerical field written as a string. Yep. Because in 95% of the time the value is an int, and the remaining 5%, it will be an X. So we made this a string.

I have to made a query based on a value chosen by the user. The problem is that I also need to check if the value is higher or lower.

Here's my query:

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT > 5);

Is there a way to do this?

10
  • You need to parse it into an int and handle error cases. Commented Jul 25, 2013 at 19:04
  • 4
    it will be an X? why not make it int? instead and remove the whole "X" concept Commented Jul 25, 2013 at 19:05
  • It's true that if it is null, then I just have to display an X. Haven't thought about that. Commented Jul 25, 2013 at 19:06
  • But it won't work because of the nature of the items I'm using. The field sometimes may be null, and sometimes may be 0 and be a valid value. Commented Jul 25, 2013 at 19:07
  • 1
    But I have three cases to check: if the value is X, if the value is null, or if the value is 0. How can I identify the three cases? Commented Jul 25, 2013 at 19:09

11 Answers 11

2

It sounds like you are trying to represent the omission of a value as an X. A Nullable type may work better. Change the type from string to int?.

public int? CARD_MANA_CONVT { get; set; }

Then:

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT.HasValue &&
                                        _item.CARD_MANA_CONVT > 5);
Sign up to request clarification or add additional context in comments.

5 Comments

No, this appears to be for Magic the Gathering, where 'X' is a valid value.
Then what does X mean exactly?
you can abstract away the X concept, if its null display as X, thereby, 0 and other numbers become 'valid' numbers. Its merely representational
It might make sense to make a custom struct is X is a valid state.
@Aniket, in this case, X != null. X is a wildcard value.
2

You could use Int.TryParse

var cardsList = cardList.Where(_item => {
                           int conv;
                           return int.TryParse(_item.CARD_MANA_CONVT, out conv) && 
                             conv > 5;
                           });

if X is supposed to be >5 then

var cardsList = cardList.Where(_item => {
                           int conv;
                           return _item.CARD_MANA_CONVT == "X" || 
                                  (
                                  int.TryParse(_item.CARD_MANA_CONVT, out conv) && 
                                  conv > 5
                                  );
                           });

If you find this makes your queries harder to read then you can extract out to an extension method.

public static class ManaHelper {
    public static bool IsGreaterThan(this string mana, int value, bool includeX) {

        if (mana == "X") return includeX;
        int manaValue;
        return int.TryParse(mana, out manaValue) && manaValue > value;
    }
}

Then you can do:

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT.IsGreaterThan(5,false));

or to include X in the results

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT.IsGreaterThan(5,true));

5 Comments

Well, what I wonder is if it will crash or break when it tries to parse the X valor?
@HerveS int.TryParse returns true or false depending on whether it can parse the value, so you get false with the X value and it then shortcuts the second comparison. It shouldn't crash or break. The second code sample is if you want a value of X to be considered >5 and so included
Well, I don't know if it's a sign, but I get a The wait operation timed out error. Will have to check out why.
In all the cases I get the same error. I suspect it is not because of your code, but rather because of the mass of data that needs to be sorted out by the query. Will investigate on that.
@HerveS you could using the parallel extensions... cardList.AsParallel().Where...
1

It should be

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT != null && _item.CARD_MANA_CONVT > 5);

should work, if CARD_MANA_CONVT is declared int? instead.

Comments

1

I'm guessing that your program has to do with Magic the Gathering, so my first suggestion would be to treat cards with converted mana cost "X" as -1, and if you need them to be sorted last rather than first include an if statement that if card A has CMC -1, it is automatically last (or you can write a custom iComparer that does the same thing). Anyway, going with what you have there, parsing the string would be one option, and could be done as such (I don't remember the C# operator overload syntax offhand, so there may be a syntax error here):

 public bool operator_> (string b)
 {
    if (this.CARD_MANA_CONVT == 'X')
        return true;
    else 
        int a = int.Parse(this.CARD_MANA_CONVT);
    if (b == 'X')
        return false;
    else
        int b = int.Parse(b);
    return a>b;
 }

EDIT: Changed overload from < to > and fixed the method to reflect it.

Comments

1

This will identify the case where it's not null and greater than five:

var cardsList = cardList.Where(_item =>
    _item.CARD_MANA_CONVT != null &&
    _item.CARD_MANA_CONVT.All(char.IsNumeric) &&
    Convert.ToInt32(_item.CARD_MANA_CONVT) > 5);

If you need to identify more cases, then you need to write more queries because these queries are linear in nature and can't return multiple sets of data. For example, if you needed to know where you needed to display "X" instead you'd need this query:

var cardsListNulls = cardList.Where(_item => _item.CARD_MANA_CONVT == null);

and then you could combine those lists:

var list = cardsList.Concat(cardsListNulls);

Comments

1

Write a method for trying to parse to int.

 public static int ParseToint(string text)
    {
        int value;
        if (int.TryParse(text, out value))
            return value;
        else return 0;
    }

amd them just call it in your expression

var cardsList = cardList.Where(_item => ParseToint(_item.CARD_MANA_CONVT) > 5);

Comments

1

The header of your question talks about using the > operator with strings. I caution you to read up on globalization and string comparisons, because the current thread culture can have an impact.

I think you need to implement IComparable<T> in this case.

public class Mana : IComparable<Mana>
    {
        private readonly string _value;

        public Mana(string value)
        {
            _value = value;             
        }

        public int CompareTo(Mana other)
        {
            if (Value == "X")
                return 1;
            if (other.Value == "X")
                return -1;
            return Convert.ToInt32(Value).CompareTo(Convert.ToInt32(other.Value));
        }
    }

Note: this isn't production ready, especially if you care about color, and you'll have to decide how X compares to other values. As @Namfuak showed, you can overload an operator if you'd like, though I'd suggest against it because mana doesn't operate like a number.

You may also want to consider putting a method on Card like:

public Mana GetConvertedCost()
{
    var convertedValue = Value != "X" ? Value : "0";
    return new Mana(convertedValue);                
}

Comments

1

This might be one of some possible solutions

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT != "X" && Convert.ToInt32(_item.CARD_MANA_CONVT) > 5);

I don't include more guarded clauses because you have said "in 95% of the time the value is an int, and the remaining 5%, it will be an X."

Comments

1
int outValue = -1;    
var cardsList = cardList.Where(item => Int32.TryParse(item.CARD_MANA_CONVT, out outValue) && outValue > 5);

The above query returns all the elements in cardList with CARD_MANA_CONVT values greater than 5, but they do not return elements with CARD_MANA_CONVT = "X"

Comments

0

I've tried a lot of ways and I've found solution, use this post that really works: string.Compare()

Comments

-3

Try this

var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT.HasValue && Convert.ToInt32(C_item.CARD_MANA_CONVT) > 5);

3 Comments

-1 because Convert.ToInt32(C_item.CARD_MANA_CONVT) will throw an exception when the values is "x" as it can be as posted by OP
He mentioned Value is either null or valid integer. Has value check for null and Convert takes care of valid integer
@Jasti You misread it, he said 'Because in 95% of the time the value is an int, and the remaining 5%, it will be an X'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.