Split string, convert ToList<int>() in one line - c#

I have a string that has numbers
string sNumbers = "1,2,3,4,5";
I can split it then convert it to List<int>
sNumbers.Split( new[] { ',' } ).ToList<int>();
How can I convert string array to integer list?
So that I'll be able to convert string[] to IEnumerable

var numbers = sNumbers?.Split(',')?.Select(Int32.Parse)?.ToList();
Recent versions of C# (v6+) allow you to do null checks in-line using the null-conditional operator

You can also do it this way without the need of Linq:
List<int> numbers = new List<int>( Array.ConvertAll(sNumbers.Split(','), int.Parse) );
// Uses Linq
var numbers = Array.ConvertAll(sNumbers.Split(','), int.Parse).ToList();

Better use int.TryParse to avoid exceptions;
var numbers = sNumbers
.Split(',')
.Where(x => int.TryParse(x, out _))
.Select(int.Parse)
.ToList();

Joze's way also need LINQ, ToList() is in System.Linq namespace.
You can convert Array to List without Linq by passing the array to List constructor:
List<int> numbers = new List<int>( Array.ConvertAll(sNumbers.Split(','), int.Parse) );

It is also possible to int array to direct assign value.
like this
int[] numbers = sNumbers.Split(',').Select(Int32.Parse).ToArray();

You can use new C# 6.0 Language Features:
replace delegate (s) => { return Convert.ToInt32(s); } with
corresponding method group Convert.ToInt32
replace redundant constructor call: new Converter<string, int>(Convert.ToInt32) with: Convert.ToInt32
The result will be:
var intList = new List<int>(Array.ConvertAll(sNumbers.Split(','), Convert.ToInt32));

also you can use this Extension method
public static List<int> SplitToIntList(this string list, char separator = ',')
{
return list.Split(separator).Select(Int32.Parse).ToList();
}
usage:
var numberListString = "1, 2, 3, 4";
List<int> numberList = numberListString.SplitToIntList(',');

On Unity3d, int.Parse doesn't work well. So I use like bellow.
List<int> intList = new List<int>( Array.ConvertAll(sNumbers.Split(','),
new Converter<string, int>((s)=>{return Convert.ToInt32(s);}) ) );
Hope this help for Unity3d Users.

My problem was similar but with the inconvenience that sometimes the string contains letters (sometimes empty).
string sNumbers = "1,2,hh,3,4,x,5";
Trying to follow Pcode Xonos Extension Method:
public static List<int> SplitToIntList(this string list, char separator = ',')
{
int result = 0;
return (from s in list.Split(',')
let isint = int.TryParse(s, out result)
let val = result
where isint
select val).ToList();
}

Why stick with just int when we have generics?
What about an extension method like :
public static List<T> Split<T>(this string #this, char separator, out bool AllConverted)
{
List<T> returnVals = new List<T>();
AllConverted = true;
var itens = #this.Split(separator);
foreach (var item in itens)
{
try
{
returnVals.Add((T)Convert.ChangeType(item, typeof(T)));
}
catch { AllConverted = false; }
}
return returnVals;
}
and then
string testString = "1, 2, 3, XP, *, 6";
List<int> splited = testString.Split<int>(',', out _);

You can use this:
List<Int32> sNumberslst = sNumbers.Split(',').ConvertIntoIntList();

Related

using Func<string, bool>, how can I split on a character then count the length of those values within a function

Essentially, I need to split a string like "aaaaa.bbbbbbbb.cccccc" on the . and then count the length of the split values using a function.
Func<string, bool> length = f => f.Split(".").Length > 1;
pretty much this but instead of counting the length of the split array, I need to count how many letters per entry of the array and see if they are over a certain length.
If you need a boolean answer, then it's either one of the following (depdending on if you want at least one substring with length > 1 or you want all of them:
Func<string, bool> length1 = f => f.Split('.').Any(s => s.Length > 1);
Func<string, bool> length2 = f => f.Split('.').All(s => s.Length > 1);
I think you are trying to do this:
string input = "aaaaa.bbbbbbbb.cccccc";
var parts = input.Split('.');
var lengths = parts.Select(e=>e.Count());
If you mean per letter:
aaaaa.bbbbbbbb.cccccc -> a = 5, b = 8, c = 6
Func<string, IEnumerable<int>> length = f => f.Split('.').Select(a => a.Length)
From what I understand, you need to take a string, split it only by the delimiter '.', and then count to see if each split value is greater than 1.
If so, you can use the following:
Func<string, bool> length = str => str.Split('.').All(s => s.Length > 1);
This will first split the string by your delimiter, then iterate on all of the values to check if they are greater than 1.
Quick test case:
string test1 = "aaa.b.ccccccc";
string test2 = "aaaaaa.bbb.c";
string test3 = "aaa.bbb.ccccc";
Console.WriteLine(length(test1)); // false, as b is 1, not greater
Console.WriteLine(length(test2)); // false, for similar reasons
Console.WriteLine(length(test3)); // true, all are greater
Another way using a func delegate:
Func<string, Tuple<string[], int[]>> length = (str) => {
string[] stringParts = str.Split('.');
int[] countLetters = stringParts.Select(s => s.Length).ToArray();
return new Tuple<string[], int[]>(stringParts, countLetters);
};
string input = "aaaaa.bbbbbbbb.cccccc";
var res = length(input);
string[] strs = res.Item1;
int[] countLetter = res.Item2;
for (int i = 0; i < strs.Length; i++)
{
Console.WriteLine(strs[i]);
Console.WriteLine(countLetter[i]);
}
Output:
aaaaa
5
bbbbbbbb
8
cccccc
6
An extension method would perhaps be an easier way to do this.
How about you write a method that returns list of strings that above the length you specify, something like this:
IEnumerable<string> GetSplittedAboveLimit(string inputString,int limit)
{
var splitted = inputString.Split(".");
foreach(var input in splitted)
{
if(input.Length > limit)
{
yield return input;
}
}
}
what about this [Example reference]:
Func<string, List<int>> length = f => f.Split('.').Select(x=>x.Length).ToList();
And call the method like this:
string inputStr = "aaaaa.bbbbbbbb.cccccc";
Console.WriteLine(String.Join(",",length(inputStr))); // prints 5,8,6
Please note: the second parameter in the Func denotes the return type, Here in the example I used it as List<int> that's why I added .ToList() at the end of the code. You can change the return types accordingly. If you are ok with IEnumerable<int> then
Func<string, IEnumerable<int>> length = f => f.Split('.').Select(x=>x.Length)
is enough.

List with arrays into seperate arrays

I have a constructor which uses a List parameter. Inside that list I have three items which are 3 integer arrays.
public HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
Now I want to initialize three new integer arrays with the arrays inside that list. But when I try this code, the index of my new arrays stay 0.
for (int i = 0; i < histogramXValues.Length; i++)
{
rArray = separateRGB.Select(obj => obj.Item1[i]).ToArray();
gArray = separateRGB.Select(obj => obj.Item2[i]).ToArray();
bArray = separateRGB.Select(obj => obj.Item3[i]).ToArray();
}
Anyone got any suggestions on how to fix this?
Bear in mind, if you have a list of N tuples, you start with 3 x N arrays. Sounds like you want them combined into 3 arrays, each containing all of the elements throughout the list. Which you can do with SelectMany.
rArray = separateRGB.SelectMany(obj => obj.Item1).ToArray();
gArray = separateRGB.SelectMany(obj => obj.Item2).ToArray();
bArray = separateRGB.SelectMany(obj => obj.Item3).ToArray();
Full example:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
static public void HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
{
var rArray = separateRGB.SelectMany(obj => obj.Item1).ToArray();
var gArray = separateRGB.SelectMany(obj => obj.Item2).ToArray();
var bArray = separateRGB.SelectMany(obj => obj.Item3).ToArray();
Console.WriteLine("rArray = {{{0}}}", string.Join(",", rArray));
Console.WriteLine("gArray = {{{0}}}", string.Join(",", gArray));
Console.WriteLine("bArray = {{{0}}}", string.Join(",", bArray));
}
public static void Main()
{
var mockData = new List<Tuple<int[], int[], int[]>>
{
Tuple.Create(new[] {11,12,13}, new[] {14,15,16}, new[] {17,18,19}),
Tuple.Create(new[] {21,22,23}, new[] {24,25,26}, new[] {27,28,29}),
Tuple.Create(new[] {31,32,33}, new[] {34,35,36}, new[] {37,38,39})
};
HistogramLogic(mockData);
}
}
Output:
rArray = {11,12,13,21,22,23,31,32,33}
gArray = {14,15,16,24,25,26,34,35,36}
bArray = {17,18,19,27,28,29,37,38,39}
Click here for code on DotNetFiddle
You can just get the item from touple
rArray = separateRGB.Select(obj => obj.Item1);
Like they sad in comments you did reassign local member in each loop.
You could use something like this.
public HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
{
List<int> rList = new List<int>();
List<int> gList = new List<int>();
List<int> bList = new List<int>();
separateRGB.ForEach((Tuple<int[], int[], int[]> tpl) =>
{
rList.AddRange(tpl.Item1);
gList.AddRange(tpl.Item1);
bList.AddRange(tpl.Item1);
});
rArray = rList.ToArray();
gArray = gList.ToArray();
bArray = bList.ToArray();
}
If you wish to not use temp List object you should know final count of elements in tuple, create local array member to desired size. and fill it. List are more suitable for adding and expanding elements. Maybe you could use one Linq Statement but if I understand goal is to get one int[] array per color. If you take
separateRGB.AsQueryable().Select(m => m.Item1).ToArray();
as a result you get int[][] result instead of simple int array;

C# Sort Lithuanian Letters

I need sort letters from file as alphabet. How can i do this? I need ToString method. Now console prints:
ABCDEFGIJKLM...ĄČĖĮ...
I need to get this:
AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ
Thanks
static char[] Letters(string e) //
{
e = e.ToUpper();
char[] mas = new char[32];
int n = 0;
foreach (char r in e)
if (Array.IndexOf(mas, r) < 0)
if (Char.IsLetter(r))
mas[n++] = r;
Array.Resize(ref mas, n);
Array.Sort(mas);
return mas;
}
You can solve this by sorting the characters using a comparer that understands how to compare characters alphabetically (the default is ordinal comparison).
This implementation is very inefficient, because it converts chars to strings every time it does a compare, but it works:
public class CharComparer : IComparer<char>
{
readonly CultureInfo culture;
public CharComparer(CultureInfo culture)
{
this.culture = culture;
}
public int Compare(char x, char y)
{
return string.Compare(new string(x, 1), 0, new string(y, 1), 0, 1, false, culture);
}
}
(Note: The culture is not actually necessary here; it works without it. I just included it for completeness.)
Then you can use that with sort functions that accept anIComparer, such as Array.Sort():
static void Main()
{
var test = "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ".ToCharArray();
Console.OutputEncoding = System.Text.Encoding.Unicode;
Array.Sort(test);
Console.WriteLine(new string(test)); // Wrong result using default char comparer.
Array.Sort(test, new CharComparer(CultureInfo.GetCultureInfo("lt"))); // Right result using string comparer.
Console.WriteLine(new string(test));
}
An alternative approach is to use an array of single-character strings rather than an array of chars, and sort that instead. This works because the sort functions will use the string comparer, which understands alphabetical order:
var test = "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ".Select(x => new string(x, 1)).ToArray();
Console.OutputEncoding = System.Text.Encoding.Unicode;
Array.Sort(test); // Correct result because it uses the string comparer, which understands alphabetical order.
Console.WriteLine(string.Concat(test));
Or using Linq:
var test = "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ".Select(x => new string(x, 1)).ToArray();
Console.OutputEncoding = System.Text.Encoding.Unicode;
// Correct result because it uses the string comparer, which understands alphabetical order.
test = test.OrderBy(x => x).ToArray();
Console.WriteLine(string.Concat(test));
Using an array of strings instead of an array of chars is probably more performant when sorting like this.
You could use following method to remove diacritics:
static string RemoveDiacritics(string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
Then you can use those chars for the ordering:
string e = "ABCDEFGIJKLM...ĄČĖĮ...";
var normalizedCharList = e.Zip(RemoveDiacritics(e), (chr, n) => new { chr, normValue = (int)n }).ToList();
var orderedChars = normalizedCharList.OrderBy(x => x.normValue).Select(x => x.chr);
string ordered = new String(orderedChars.ToArray());

Split string into List<int> ignore none int values

Am using the following code to split a string into a List<int>, however occasionally the string includes non integer values, which are handled differently.
An example string might be like: 1,2,3,4,x
code looks like:
List<int> arrCMs = new List<int>(strMyList.Split(',').Select(x => int.Parse(x)));
The problem is as soon as it hits the 'x' it throws an error because 'x' can't be parsed as an integer.
How can I make it ignore non integer values? I'm sure I should be able to do something with int.TryParse but can't quite figure it out.
Thanks
List<int> arrCMs = strMyList.Split(',')
.Select(possibleIntegerAsString => {
int parsedInteger = 0;
bool isInteger = int.TryParse(possibleIntegerAsString , out parsedInteger);
return new {isInteger, parsedInteger};
})
.Where(tryParseResult => tryParseResult.isInteger)
.Select(tryParseResult => tryParseResult.parsedInteger)
.ToList();
The first Select in the above example returns an anonymous type that describes the result of int.TryParse - that is, whether it was a valid integer, and if so, what the value was.
The Where clause filters out those that weren't valid.
The second Select then retrieves the parsed values from the strings that were able to be parsed.
Short and sweet, using int.TryParse:
List<int> nums = list
.Split(',')
.Select(i =>
{
int val;
return int.TryParse(i, out val) ? (int?)val : null;
})
.Where(i => i.HasValue)
.Cast<int>()
.ToList()
Working Example: http://dotnetfiddle.net/4wyoAM
Change this
int result;
List<int> arrCMs =
new List<int>(strMyList.Split(',')
.Where(x => int.TryParse(x, out result))
.Select(int.Parse));
another one, using Array.ForEach
List<int> ints = new List<int>();
Array.ForEach(strMyList.Split(','), s =>
{
int i;
if (int.TryParse(s, out i)){ ints.Add(i);}
});
Plot twist: use an old-school foreach loop.
List<int> arrCMs = new List<int>();
foreach (string str in strMyList.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
int res;
if (int.TryParse(str, out res))
{
arrCMs.Add(res);
}
}
You could also create a method for it and make use of an iterator block by using yield return:
public static IEnumerable<int> ParseIntegers(string val, char seperator = ',')
{
foreach (string str in val.Split(new [] { seperator }, StringSplitOptions.RemoveEmptyEntries))
{
int res;
if (int.TryParse(str, out res))
{
yield return res;
}
}
}
This is probably over-engineering if it's only for one time use.
Parse once only for each value, but a bit tricky.
int result = 0;
List<int> arrCMs = strMyList.Split(',')
.Where(x => int.TryParse(x, out result))
.Select(x => result)
.ToList();

Split a string of Number and characters

I had a List liRoom which contains a alphanumeric and Alphabetic string For Example
List<string> liRoom = new List<string>() {"Room1","Room2","Room3",
"Room4","Hall","Room5","Assembly",
"Room6","Room7","Room8","Room9};
This List is of type Alphanumeric and Alphabetic so i want to take the max numeric value from this list of string.
I had tried to do it this way
var ss = new Regex("(?<Alpha>[a-zA-Z]+)(?<Numeric>[0-9]+)");
List<int> liNumeric = new List<int>();
foreach (string st in liRoom)
{
var varMatch = ss.Match(st);
liNumeric.Add(Convert.ToInt16(varMatch.Groups["Numeric"].Value));
}
int MaxValue = liNumeric.Max();// Result Must be 9 from above Example.
And
List<int> liNumeric = new List<int>();
foreach (string st in liRoom)
{
liNumeric.Add( int.Parse(new string(st.Where(char.IsDigit).ToArray())));
}
int MaxValue = liNumeric.Max();// Result Must be 9 from above Example.
But both shows error when st is Hall,Assembly
Help me How to do this.
there are few reasons you will get exception in your code. I'm adding few condition for those possible exceptions.
List<int> liNumeric = new List<int>();
foreach (string st in liRoom)
{
// int.Parse will fail if you don't have any digit in the input
if(st.Any(char.IsDigit))
{
liNumeric.Add(int.Parse(new string(st.Where(char.IsDigit).ToArray())));
}
}
if (liNumeric.Any()) //Max will fail if you don't have items in the liNumeric
{
int MaxValue = liNumeric.Max();
}
Please try the following:
List<string> liRoom = new List<string>() {"Room1","Room2","Room3",
"Room4","Hall","Room5","Assembly",
"Room6","Room7","Room8","Room9"};
var re = new Regex(#"\d+");
int max = liRoom.Select(_ => re.Match(_))
.Where(_ => _.Success)
.Max( _ => int.Parse(_.Value));
/*
max = 9
*/
You don't need foreach, it can be done with one statement:
int value = liRoom.Where(x => x.Any(char.IsDigit))
.Select(x => Convert.ToInt32(new String(x.Where(char.IsDigit).ToArray())))
.Max();
It seems odd but it's working. :)
You should add below in your code by checking whether match is success or not
if (varMatch.Success)
{
liNumeric.Add(Convert.ToInt16(varMatch.Groups["Numeric"].Value));
}

Categories