Selecting max number from a list of string in LINQ? - c#

trying to select the max digit from a list of strings:
int maxDigit = this.myList.Where(x=> x.Name.Any(Char.IsDigit))
.Select(x => int.Parse(x.Name)).DefaultIfEmpty(0).Max();
It is int.Parse(x.Name) which is causing an exception as this is returning the entire name string e.g. 'myValue99' which of course cannot be parsed to an int. I just want to return 99. I don't know where the digits will be in the string therefore cannot for example take the last two.
I need the DefaultIfEmpty for cases where the string does not contain a number.

Assuming you want the max number and not the max digit, all you need is a function to convert "stuff99" to 99. Then the Linq part becomes child's play:
int maxNumber = myList.Max(ExtractNumberFromText);
or, to be closer to your specs:
int maxNumber = myList
.Select(ExtractNumberFromText)
.DefaultIfEmpty(0)
.Max();
#Codecaster already pointed to a few applicable answers on this site for the second part. I adopted a simple one. No error checking.
// the specs: Only ever going to be my stuff1, stuff99
int ExtractNumberFromText(string text)
{
Match m = Regex.Match(text, #"\d*");
return int.Parse(m.Groups[0].Value); // exception for "abc"
// int.Parse("0" + m.Groups[0].Value); // use this for default to 0
}

you should only select and parse the Digit characters out of your string
int maxDigit = this.myList.Where(x => x.Name.Any(Char.IsDigit))
.Select(x => int.Parse(new string(x.Name.Where(Char.IsDigit).ToArray())))
.DefaultIfEmpty(0).Max();

Assuming the input can contain the following categories:
nulls
Empty strings
Strings with only alphabetical characters
Strings with mixed alphabetical and numerical characters
Strings with only numerical characters
You want to introduce a method that extracts the number, if any, or returns a meaningful value if not:
private static int? ParseStringContainingNumber(string input)
{
if (String.IsNullOrEmpty(input))
{
return null;
}
var numbersInInput = new String(input.Where(Char.IsDigit).ToArray());
if (String.IsNullOrEmpty(numbersInInput))
{
return null;
}
int output;
if (!Int32.TryParse(numbersInInput, out output))
{
return null;
}
return output;
}
Note that not all characters for which Char.IsDigit returns true can be parsed by Int32.Parse(), hence the TryParse.
Then you can feed your list to this method:
var parsedInts = testData.Select(ParseStringContainingNumber)
.Where(i => i != null)
.ToList();
And do whatever you want with the parsedInts list, like calling IEnumerable<T>.Max() on it.
With the following test data:
var testData = new List<string>
{
"۱‎", // Eastern Arabic one, of which Char.IsDigit returns true.
"123",
"abc456",
null,
"789xyz",
"foo",
"9bar9"
};
This returns:
123
456
789
99
Especially note the latest case.

To find the max digit (not number) in each string:
static void Main(string[] args)
{
List<string> strList = new List<string>() { "Value99", "46Text" };
List<int> resultList = new List<int>();
foreach (var str in strList)
{
char[] resultString = Regex.Match(str, #"\d+").Value.ToCharArray();
int maxInt = resultString.Select(s => Int32.Parse(s.ToString())).Max();
resultList.Add(maxInt);
}
}

It can be simple using Regex.
You stated 99, so you need to span more than one digit:
var maxNumber = myTestList.SelectMany(x => getAllNumnbersFromString(x.Name)).DefaultIfEmpty(0).Max();
static List<int> getAllNumnbersFromString(string str)
{
List<int> results = new List<int>();
var matchesCollection = Regex.Matches(str, "[0-9]+");
foreach (var numberMatch in matchesCollection)
{
results.Add(Convert.ToInt32(numberMatch.ToString()));
}
return results;
}
One digit only check:
int maxNumber = myTestList.SelectMany(x => x.Name.ToCharArray().ToList())
.Select(x => Char.IsDigit(x) ? (int)Char.GetNumericValue(x) : 0)
.DefaultIfEmpty(0).Max();

Probably there's a slicker way to do this but I would just do:
int tmp = 0;
int maxDigit = this.myList.Where(x=> x.Name.Any(Char.IsDigit))
.Select(x =>
(int.TryParse(x.Name,out tmp ) ? int.Parse(x.Name) : 0 ) ).Max();
You have to remember that Parse will error out if it can't parse the value but TryParse will just give you false.

Related

Extract multiple integers from string and store as int

I know that this will extract the number and store as int -
string inputData = "sometex10";
string data = System.Text.RegularExpressions.Regex.Match(inputData, #"\d+").Value;
int number1 = Convert.ToInt32(data);
I am trying to extract multiple numbers from a string eg- 10 + 2 + 3 and store these as separate integers.
note : the amount of numbers the user will type in is unknow.
Any suggestions much appreciated thanks
You can use a LINQ one-liner:
var numbers = Regex.Matches(inputData, #"\d+").Select(m => int.Parse(m.Value)).ToList();
Or use ToArray() if you prefer an array instead of a list.
C# program that uses Regex.Split
Referencing : http://www.dotnetperls.com/regex-split
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
//
// String containing numbers.
//
string sentence = "10 cats, 20 dogs, 40 fish and 1 programmer.";
//
// Get all digit sequence as strings.
//
string[] digits = Regex.Split(sentence, #"\D+");
//
// Now we have each number string.
//
foreach (string value in digits)
{
//
// Parse the value to get the number.
//
int number;
if (int.TryParse(value, out number))
{
Console.WriteLine(number);
}
}
}
}
You can use something like this:
string inputData = "sometex10";
List<int> numbers = new List<int>();
foreach(Match m in Regex.Matches(inputData, #"\d+"))
{
numbers.Add(Convert.ToInt32(m.Value));
}
This will store the integers in the list numbers

What is the best way to check if a string can be parsed into an int array?

I need to determine if a string can be parsed into an array of int. The string MAY be in the format
"124,456,789,0"
In case which can it can converted thus:
int[] Ids = SearchTerm.Split(',').Select(int.Parse).ToArray();
However the string may also be something like:
"Here is a string, it is very nice."
In which case the parsing fails.
The logic currently branches in two directions based on whether the string contains a comma character (assuming that only the array-like strings will contain this character) but this logic is now flawed and comma characters are now appearing in other strings.
I could put a Try..Catch around it but I am generally adverse to controlling logic flow by exceptions.
Is there an easy way to do this?
I could put a Try..Catch around it but I am generally adverse to controlling logic flow by exceptions
Good attitude. If you can avoid the exception, do so.
A number of answers have suggested
int myint;
bool parseFailed = SearchTerm.Split(',')
.Any( s => !int.TryParse(s, out myint));
Which is not bad, but not great either. I would be inclined to first, write a better helper method:
static class Extensions
{
public static int? TryParseAsInteger(this string s)
{
int j;
bool success = int.TryParse(s, out j);
if (success)
return j;
else
return null;
}
}
Now you can say:
bool parseFailed = SearchTerm.Split(',')
.Any( s => s.TryParseAsInteger() == null);
But I assume that what you really want is the parsed state if it can succeed, rather than just answering the question "would a parse succeed?" With this helper method you can say:
List<int?> parse = SearchTerm.Split(',')
.Select( s => s.TryParseAsInteger() )
.ToList();
And now if the list contains any nulls, you know that it was bad; if it doesn't contain any nulls then you have the results you wanted:
int[] results = parse.Contains(null) ? null : parse.Select(x=>x.Value).ToArray();
int myint;
bool parseFailed = SearchTerm.Split(',')
.Any( s => !int.TryParse(s, out myint));
You can use multiline lambda expression to get int.TryParse for every Split method result:
var input = "124,456,789,0";
var parts = input.Split(new [] {","}, StringSplitOptions.RemoveEmptyEntries);
var numbers
= parts.Select(x =>
{
int v;
if (!int.TryParse(x, out v))
return (int?)null;
return (int?)v;
}).ToList();
if (numbers.Any(x => !x.HasValue))
Console.WriteLine("string cannot be parsed as int[]");
else
Console.WriteLine("OK");
It will not only check if value can be parsed to int, but also return the value if it can, so you don't have to do the parsing twice.
you can use RegEx to determine if the string match your pattern
something like this
string st = "124,456,789,0";
string pattS = #"[0-9](?:\d{0,2})";
Regex regex = new Regex(pattS);
var res = regex.Matches(st);
foreach (var re in res)
{
//your code here
}
tested on rubular.com here
How about,
int dummy;
var parsable = SearchTerm.Split(',').All(s => int.TryParse(s, out dummy));
but if you are doing that you might as well just catch the exception
Why dont you first remove the characters from the string and use
bool res = int.TryParse(text1, out num1);
Example below has no limit.
The BigInteger type is an immutable type that represents an arbitrarily large integer whose value in theory has no upper or lower bounds.
BigInteger MSDN
string test = "20,100,100,100,100,100,100";
test = test.Replace(",", "");
BigInteger num1 = 0;
bool res = BigInteger.TryParse(test, out num1);

Generic extraction of multiple decimals using Regular expressions

Hi how do you extract multiple decimals with different number of decimal places from a string?
I'm looking to find a generic way to extract 3 numbers out the following strings.
e.g
CC77X1722X12 => 77,1722,12
PC77.5X10102X12.5 => 77.5, 10102, 12.5
XP60.25X0.333X12 => 60.25, 0.333, 12
The three numbers are always separated by 'X', and the string always starts with 2 characters
Thanks!
Since you have such a specific pattern, you don't even need to use regular expressions. Because the first two characters can be ignored and all the numbers are separated by 'X' characters, this C# code should do the trick (with appropriate error handling added, of course)
public IEnumerable<decimal> ExtractNumbers(string s)
{ // For s = "CC77X1722X12"
string[] nums = s.Substring(2).Split('X'); // nums = ["77", "1722", "12"];
return nums.Select(num => decimal.Parse(num)); // returns [77, 1722, 12]
}
For production code, though, I would recommend decimal.TryParse over decimal.Parse. To use that method, you could write something like
public IEnumerable<decimal> ExtractNumbers(string s)
{
string[] nums = s.Substring(2).Split('X');
return nums
.Select(num => {
decimal d;
if (decimal.Parse(num, out d))
return new {Number = d, Succeeded = true};
return new {Number = 0, Succeeded = false};
})
.Filter(result => result.Succeeded)
.Select(result => result.Number);
}

How can I parse the int from a String in C#?

I have a string that contains an int. How can I parse the int in C#?
Suppose I have the following strings, which contains an integer:
15 person
person 15
person15
15person
How can I track them, or return null if no integer is found in the string?
You can remove all non-digits, and parse the string if there is anything left:
str = Regex.Replace(str, "\D+", String.Empty);
if (str.Length > 0) {
int value = Int32.Parse(str);
// here you can use the value
}
Paste this code into a test:
public int? ParseAnInt(string s)
{
var match = System.Text.RegularExpressions.Regex.Match(s, #"\d+");
if (match.Success)
{
int result;
//still use TryParse to handle integer overflow
if (int.TryParse(match.Value, out result))
return result;
}
return null;
}
[TestMethod]
public void TestThis()
{
Assert.AreEqual(15, ParseAnInt("15 person"));
Assert.AreEqual(15, ParseAnInt("person 15"));
Assert.AreEqual(15, ParseAnInt("person15"));
Assert.AreEqual(15, ParseAnInt("15person"));
Assert.IsNull(ParseAnInt("nonumber"));
}
The method returns null is no number is found - it also handles the case where the number causes an integer overflow.
To reduce the chance of an overflow you could instead use long.TryParse
Equally if you anticipate multiple groups of digits, and you want to parse each group as a discreet number you could use Regex.Matches - which will return an enumerable of all the matches in the input string.
Use something like this :
Regex r = new Regex("\d+");
Match m = r.Match(yourinputstring);
if(m.Success)
{
Dosomethingwiththevalue(m.Value);
}
Since everyone uses Regex to extract the numbers, here's a Linq way to do it:
string input = "15person";
string numerics = new string(input.Where(Char.IsDigit).ToArray());
int result = int.Parse(numerics);
Just for the sake of completeness, it's probably not overly elegant. Regarding Jaymz' comment, this would return 151314 when 15per13so14n is passed.

How can I parse an integer and the remaining string from my string?

I have strings that look like this:
1. abc
2. def
88. ghi
I'd like to be able to get the numbers from the strings and put it into a variable and then get the remainder of the string and put it into another variable. The number is always at the start of the string and there is a period following the number. Is there an easy way that I can parse the one string into a number and a string?
May not be the best way, but, split by the ". " (thank you Kirk)
everything afterwards is a string, and everything before will be a number.
You can call IndexOf and Substring:
int dot = str.IndexOf(".");
int num = int.Parse(str.Remove(dot).Trim());
string rest = str.Substring(dot).Trim();
var input = "1. abc";
var match = Regex.Match(input, #"(?<Number>\d+)\. (?<Text>.*)");
var number = int.Parse(match.Groups["Number"].Value);
var text = match.Groups["Text"].Value;
This should work:
public void Parse(string input)
{
string[] parts = input.Split('.');
int number = int.Parse(parts[0]); // convert the number to int
string str = parts[1].Trim(); // remove extra whitespace around the remaining string
}
The first line will split the string into an array of strings where the first element will be the number and the second will be the remainder of the string.
Then you can convert the number into an integer with int.Parse.
public Tuple<int, string> SplitItem(string item)
{
var parts = item.Split(new[] { '.' });
return Tuple.Create(int.Parse(parts[0]), parts[1].Trim());
}
var tokens = SplitItem("1. abc");
int number = tokens.Item1; // 1
string str = tokens.Item2; // "abc"

Categories