Reputation: 2080
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
Reputation: 1363
I've tried a lot of ways and I've found solution, use this post that really works: string.Compare()
Upvotes: 0
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
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
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
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
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
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
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
Reputation: 947
Try this
var cardsList = cardList.Where(_item => _item.CARD_MANA_CONVT.HasValue && Convert.ToInt32(C_item.CARD_MANA_CONVT) > 5);
Upvotes: -3
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
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