I have multiple IDs in a List<string>()
List<string> IDList = new List<string>() {
"ID101", //101
"I2D102", //102
"103", //103
"I124D104", //104
"ID-105", //105
"-1006" }; //1006
Rule: The string always ends with the id which has length 1 to n and is int only
I need to extract them to int values. But my solution doesn't work
List<int> intList = IDList.Select(x => int.Parse(Regex.Match(x, #".*\d*").Value)).ToList();
If ID is always at the end, you could use LINQ solution instead of Regex:
var query = IDList.Select(id =>
int.Parse(new string(id.Reverse()
.TakeWhile(x => char.IsNumber(x))
.Reverse().ToArray())));
The idea is to take the characters from the last till it finds no number. Whatever you get, you convert it into int. The good thing about this solution is it really represents what you specify.
Well, according to
Rule: The string always ends with the id which has length 1 to n and
is int only
the pattern is nothing but
[0-9]{1,n}$
[0-9] - ints only
{1,n} - from 1 to n (both 1 and n are included)
$ - string always ends with
and possible implementation could be something like this
int n = 5; //TODO: put actual value
String pattern = "[0-9]{1," + n.ToString() + "}$";
List<int> intList = IDList
.Select(line => int.Parse(Regex.Match(line, pattern).Value))
.ToList();
In case there're some broken lines, say "abc" (and you want to filter them out):
List<int> intList = IDList
.Select(line => Regex.Match(line, pattern))
.Where(match => match.Success)
.Select(match => int.Parse(match.Value))
.ToList();
Here's another LINQ approach which works if the number is always at the end and negative values aren't possible. Skips invalid strings:
List<int> intList = IDList
.Select(s => s.Reverse().TakeWhile(Char.IsDigit))
.Where(digits => digits.Any())
.Select(digits => int.Parse(String.Concat(digits.Reverse())))
.ToList();
( Edit: similar to Ian's approach )
This below code extract last id as integer from collection and ignore them which end with none integer value
List<int> intList = IDList.Where(a => Regex.IsMatch(a, #"\d+$") == true)
.Select(x => int.Parse(Regex.Match(x, #"\d+$").Value)).ToList();
i assume you want the last numbers :
var res = IDList.Select(x => int.Parse(Regex.Match(x, #"\d+$").Value)).ToList();
Related
I have a substring
string subString = "ABC";
Every time all three chars appears in a input, you get one point
for example, if input is:
"AABKM" = 0 points
"AAKLMBDC" = 1 point
"ABCC" = 1 point because all three occurs once
"AAZBBCC" = 2 points because ABC is repeated twice;
etc..
The only solution I could come up with is
Regex.Matches(input, "[ABC]").Count
But does not give me what I'm looking for.
Thanks
You could use a ternary operation, where first we determine that all the characters are present in the string (else we return 0), and then select only those characters, group by each character, and return the minimum count from the groups:
For example:
string subString = "ABC";
var inputStrings = new[] {"AABKM", "AAKLMBDC", "ABCC", "AAZBBCC"};
foreach (var input in inputStrings)
{
var result = subString.All(input.Contains)
? input
.Where(subString.Contains)
.GroupBy(c => c)
.Min(g => g.Count())
: 0;
Console.WriteLine($"{input}: {result}");
}
Output
It could be done with a single line, using Linq. However I am not very confident that this could be a good solution
string subString = "ABC";
string input = "AAZBBBCCC";
var arr = input.ToCharArray()
.Where(x => subString.Contains(x))
.GroupBy(x => x)
.OrderBy(a => a.Count())
.First()
.Count();
The result is 2 because the letter A is present only two times.
Let's try to explain the linq expression.
First transform the input string in a sequence of chars, then take only the chars that are contained in the substring. Now group these chars and order them according the the number of occurrences. At this point take the first group and read the count of chars in that group.
Let's see if someone has a better solution.
try this code :
string subString = "ABC";
var input = new[] { "AABKM", "AAKLMBDC", "ABCC", "AAZBBCC" };
foreach (var item in input)
{
List<int> a = new List<int>();
for (int i = 0; i < subString.Length; i++)
{
a.Add(Regex.Matches(item, subString.ToList()[i].ToString()).Count);
}
Console.WriteLine($"{item} : {a.Min()}");
}
I have a problem about sorting array after reading all decimal numbers and integers from txt file. The file contains both decimal and integer values.
These values can be splited non-fixed space.
Here is my file like this
-12,56 76
11
-6,5 43
15
...
The result is shown like
-12,56 -6,5 11 15 76 ...
How can I do the process.
You can try Linq, SelectMany since single line can contain several numbers:
var numbers = File
.ReadLines(#"c:\myfile.txt")
.SelectMany(line => line.Split(
new char[] {' ', '\t'},
StringSplitOptions.RemoveEmptyEntries))
.Select(item => decimal.Parse(item)) //TODO: Ensure the correct Culture
.OrderBy(item => item)
.ToArray(); // Let's have numbers as an array
string result = string.Join(Environment.NewLine, numbers);
Please, note StringSplitOptions.RemoveEmptyEntries when Splitting - we remove unwanted empty chunks when processing lines like "-12,56 76"
Edit: If you want to try to detect where do we have and integer and where is decimal:
var numbers = File
.ReadLines(#"c:\myfile.txt")
.SelectMany(line => line.Split(
new char[] {' ', '\t'},
StringSplitOptions.RemoveEmptyEntries))
.Select(item => {
// if we succeed in parsing as int, it's int otherwise - decimal
bool isInt = int.TryParse(item, out var intValue);
return new {
isInteger = isInt,
integerValue = intValue,
decimalValue = decimal.Parse(item) //TODO: ensure right culture
};
}) //TODO: Ensure the correct Culture
.OrderBy(item => item.decimalValue)
.ToArray(); // Let's have numbers as an array
Now if you want integer values:
int[] ints = numbers
.Where(item => item.isInteger)
.Select(item => item.integerValue)
//.OrderBy(item => item) // uncomment, if you want to sort ints
.ToArray();
For decimals:
decimal[] decimals = numbers
.Where(item => !item.isInteger)
.Select(item => item.decimalValue)
//.OrderBy(item => item) // uncomment, if you want to sort decimals
.ToArray();
This answer is mostly the same as Dmitry's, but since it's written and it's slightly different, I figured I share.
Since the file contains both decimal and integer values, and an array can only contain one type, it makes sense to obtain an array of decimal values (since all integers can be converted to a decimal).
To split the file on all whitespace characters, we can pass an empty char[] to the Split method, which allows us to use File.ReadAllText, since it will split on the newline character(s) as well:
var result = File.ReadAllText(#"f:\public\temp\temp.txt")
.Split(new char[] {}, StringSplitOptions.RemoveEmptyEntries)
.Select(decimal.Parse)
.OrderBy(i => i)
.ToList();
It sounds like you want to be able to tell which items are integer values from this array, which we can do using the modulus operator (which returns the remainder of dividing one number by another). If a decimal number divided by 1 has no remainder, then it's an integer, so:
var integerValues = result.Where(item => item % 1 == 0).ToList();
var decimalValues = result.Where(item => item % 1 != 0).ToList();
I currently have a string that looks like this:
string numbers = "55;9;20;3";
How would i make the numbers in ascending order like this:
string numbers = "3;9;20;55";
You can try with a combination of String.Join, OrderBy and int.Parse like the following:
numbers= String.Join(";",
numbers.Split(';').OrderBy(x=> int.Parse(x)));
You can check this working example as well
You can use System.Linq namespace for this:
using System.Linq;
...
string numbers = "55;9;20;3";
string output = String.Join(",", numbers.Split(';').Select(x => int.Parse(x)).OrderBy(x => x));
I'd break this into a four step process.
// 1) Split the numbers apart using based on the delimiting character ';'
var splitString = numbers.Split(';');
// 2) Convert the array of `string` to an array of `int`
var numberArray = splitString.Select(x => int.Parse(x));
// 3) Order the array which has been output by the `Split` method.
var orderedArray = numberArray.OrderBy(x => x);
// 4) Join the string back together again in the correct order, delimited by ';'
var orderedNumbers = string.Join(";", orderedArray);
This could be squashed together into less lines of code, but by doing it in multiple stages it should give you a good understanding of what is happening.
For example, Here is the same logic in one line of code:
string orderedNumers = string.Join(";", numbers.Split(';').OrderBy(x => int.Parse(x)));
I want to define a Regular expression pattern that will give unique user counts in a file. One more thing i also want to apply length count such that Users value does not exceed more than 15 characters.
So that my code will return 2 in the logs provided below as it should discard users value exceeding length 15.
Logs file format :
User:fd441f1f-22c0-45d2-b020-32e1e6a15a73
User:fd441f1f-22c0-45d2-b020-32e1e6a15f43
User:fd441f1f-24g0-45d2-b050-32e1e6a15a73
User: karansha
User: gulanand
Code i tried:
Regex regex = new Regex(#"User:\s*(?<username>.*?)\s");
MatchCollection matches = regex.Matches(x);
foreach (Match match in matches)
{
var user = match.Groups["username"].Value;
if (!users.Contains(user)) users.Add(user);
}
int numberOfUsers = users.Count;
You can do that with LINQ:
int numberOfUsers = regex.Matches(x)
.Cast<Match>()
.Select(m => m.Groups["username"].Value)
.Distinct() // pick only unique names
.Count(name => name.Length < 15); // calculate count
Or without regular expressions:
int numberOfUsers = File("log.txt")
.ReadLines()
.Select(line => line.Replace("User:", "").Trim())
.Distinct()
.Count(name => name.Length < 15);
I wouldn't use a Regex for this.
Try using string.Split() and Distinct instead.
int numberOfUsers = x.Split(new string[] { "User:" }, StringSplitOptions.RemoveEmptyEntries)
.Distinct()
.Count(name => name.Length < 15);
string strArr="5,3,8,1,9,2,0,6,4,7";
I would like to rearrange the order of the numbers so the result will look like the following:
string result ="0,1,2,3,4,5,6,7,8,9";
Any idea?
Split, sort and join:
string[] nums = strArr.Split(',');
Array.Sort(nums);
string result = String.Join(",", nums);
Or:
string result =
String.Join(",",
strArr.Split(',')
.OrderBy(s => s)
.ToArray()
);
If you have a string with larger numbers that need to be sorted numerically, you can't sort them as strings, as for example "2" > "1000". You would convert each substring to a number, sort, and then convert them back:
string result =
String.Join(",",
strArr
.Split(',')
.Select(s => Int32.Parse(s))
.OrderBy(n => n)
.Select(n => n.ToString())
.ToArray()
);
Or, as mastoj suggested, parse the strings in the sorting:
string result =
String.Join(",",
strArr
.Split(',')
.OrderBy(s => Int32.Parse(s))
.ToArray()
);
Shorter version of one of the versions in Guffa's answer:
var res = String.Join(",", str.Split(',').OrderBy(y => int.Parse(y)).ToArray());
By splitting and joining:
string strArr = "5,3,8,1,9,2,0,6,4,7";
string[] sArr = strArr.Split(',');
Array.Sort(sArr);
string result = string.Join(",", sArr);
You can create a string array with the string.split(char[]) method.
With this array you can call the Array.Sort(T) method, that will sort the items into ascending numerical order (for your example).
With this sorted array you can call the String.Join(string, object[]) to pull it together into a string again.
string arr = "5,3,8,1,9,2,0,6,4,7";
string result = arr.Split(',').OrderBy(str => Int32.Parse(str)).Aggregate((current, next) => current + "," + next);