hsim
hsim

Reputation: 2080

Operator '>' cannot be applied to operands of type 'string' and 'string' in query

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?

Upvotes: 2

Views: 4018

Answers (11)

Almeida
Almeida

Reputation: 1363

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

Upvotes: 0

jonni
jonni

Reputation: 338

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"

Upvotes: 1

Abbas Amiri
Abbas Amiri

Reputation: 3204

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."

Upvotes: 1

Bob Vale
Bob Vale

Reputation: 18474

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));

Upvotes: 2

neontapir
neontapir

Reputation: 4736

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);                
}

Upvotes: 1

Ehsan
Ehsan

Reputation: 32651

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);

Upvotes: 1

Mike Perrenoud
Mike Perrenoud

Reputation: 67898

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);

Upvotes: 1

IllusiveBrian
IllusiveBrian

Reputation: 3204

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.

Upvotes: 1

Jasti
Jasti

Reputation: 947

Try this

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

Upvotes: -3

Aniket Inge
Aniket Inge

Reputation: 25695

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.

Upvotes: 1

Dustin Kingen
Dustin Kingen

Reputation: 21245

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);

Upvotes: 2

Related Questions