I've got the following method I created which works fine if there actually is the delimiter in question. I want to keep this out of LINQ for now...
e.g.
If I pass in the string "123;322;323" it works great.
But if I only pass in one string value without the delimiter such as "123" it obviously is not going to split it since there is no delimiter. I am just trying to figure out the best way to check and account for this and be able to spit out that one value back in the list
public static List<int> StringToList(string stringToSplit, char splitDelimiter)
{
List<int> list = new List<int>();
if (string.IsNullOrEmpty(stringToSplit))
return list;
string[] values = stringToSplit.Split(splitDelimiter);
if (values.Length < 1)
return list;
foreach (string s in values)
{
int i;
if (Int32.TryParse(s, out i))
list.Add(i);
}
return list;
}
UPDATED: This is what I came up with that seems to work but sure is long
public static List<int> StringToList(string stringToSplit, char splitDelimiter)
{
List<int> list = new IntList();
if (string.IsNullOrEmpty(stringToSplit))
return list;
if (stringToSplit.Contains(splitDelimiter.ToString()))
{
string[] values = stringToSplit.Split(splitDelimiter);
if (values.Length <= 1)
return list;
foreach (string s in values)
{
int i;
if (Int32.TryParse(s, out i))
list.Add(i);
}
}
else if (stringToSplit.Length > 0)
{
int i;
if(Int32.TryParse(stringToSplit, out i))
list.Add(i);
}
return list;
}
Change this condition:
if (values.Length <= 1)
return list;
To:
if (values.Length <= 0)
return list;
This works because String.Split will return the original string if it can't find the delimiter:
// stringToSplit does not contain the splitDelimiter
string[] values = stringToSplit.Split(splitDelimiter);
// values is a string array containing one value - stringToSplit
There are a LOT of unnecessary checks for conditions that don't matter to the core logic of the method.
public static List<int> StringToList(string stringToSplit, char splitDelimiter)
{
List<int> list = new IntList();
if (string.IsNullOrEmpty(stringToSplit))
return list;
//this if is not necessary. As others have said, Split will return a string[1] with the original string if no delimiter is found
if (stringToSplit.Contains(splitDelimiter.ToString()))
{
string[] values = stringToSplit.Split(splitDelimiter);
//why check this? if there are no values, the foreach will do nothing and fall through to a return anyway.
if (values.Length <= 1)
return list;
foreach (string s in values)
{
int i;
if (Int32.TryParse(s, out i))
list.Add(i);
}
}
//again, this is rendered redundant due to previous comments
else if (stringToSplit.Length > 0)
{
int i;
if(Int32.TryParse(stringToSplit, out i))
list.Add(i);
}
return list;
}
Try this. You hopefully have some unit tests calling this method to make sure it works...right?
public static List<int> StringToList(string stringToSplit, char splitDelimiter)
{
List<int> list = new IntList();
if (string.IsNullOrEmpty(stringToSplit))
return list;
foreach(var s in stringToSplit.Split(splitDelimiter))
{
int i;
if(int.TryParse(s, out i))
list.Add(i);
}
return list;
}
Personally, I haven't tried out your code, but it looks functional. The Split method should return an array with one element.
Since you say it's not, I believe you, and I would add this to the top of your method:
if (!stringToSplit.Contains(splitDelimiter))
{
int i;
if (Int32.TryParse(stringToSplit, out i))
list.Add(i);
return list;
}
You don't need to account for that situation, as string.Split() returns an array with a single element when no delimiter is found:
If this instance does not contain any of the strings in separator, the returned array consists of a single element that contains this instance.
See msdn at "Remarks"
Might I suggest an extension method to help you in cases like this in general?
The idea would be to yield return all results from a collection of strings that can be parsed to a specified type.
First you'd need a delegate to match the signature of your standard TryParse method:
public delegate bool Parser<T>(string input, out T value);
Then you can write an extension method that takes an instance of this delegate type and enumerates over a collection of strings, parsing everywhere it can:
// Notice: extension methods must belong to a class marked static.
public static class EnumerableParser
{
// modified code to prevent horizontal overflow
public static IEnumerable<T> ParseAll<T>
(this IEnumerable<string> strings, Parser<T> parser)
{
foreach (string str in strings)
{
T value;
if (parser(str, out value))
yield return value;
}
}
}
Now your StringToList method becomes trivial to implement:
public List<int> StringToList(string stringToSplit, char delimiter)
{
// Notice: since string.Split returns a string[], and string[] implements
// IEnumerable<string>, so the ParseAll extension method can be called on it.
return stringToSplit.Split(delimiter).ParseAll<int>(int.TryParse).ToList();
}
A shorter implementation you might consider.
public static List<int> StringToList(string stringToSplit, char splitDelimiter)
{
int i;
return stringToSplit.Split(splitDelimiter)
.Where(str => int.TryParse(str, out i))
.Select(str => int.Parse(str))
.ToList();
}
Either it must have a delimiter or, it part must have a fixed length or, the string must follow a pattern for repeat behavior.
Related
I only found a way to do it the opposite way round: create a comma separated string from an int list or array, but not on how to convert input like string str = "1,2,3,4,5"; to an array or list of ints.
Here is my implementation (inspired by this post by Eric Lippert):
public static IEnumerable<int> StringToIntList(string str)
{
if (String.IsNullOrEmpty(str))
{
yield break;
}
var chunks = str.Split(',').AsEnumerable();
using (var rator = chunks.GetEnumerator())
{
while (rator.MoveNext())
{
int i = 0;
if (Int32.TryParse(rator.Current, out i))
{
yield return i;
}
else
{
continue;
}
}
}
}
Do you think this is a good approach or is there a more easy, maybe even built in way?
EDIT: Sorry for any confusion, but the method needs to handle invalid input like "1,2,,,3" or "###, 5," etc. by skipping it.
You should use a foreach loop, like this:
public static IEnumerable<int> StringToIntList(string str) {
if (String.IsNullOrEmpty(str))
yield break;
foreach(var s in str.Split(',')) {
int num;
if (int.TryParse(s, out num))
yield return num;
}
}
Note that like your original post, this will ignore numbers that couldn't be parsed.
If you want to throw an exception if a number couldn't be parsed, you can do it much more simply using LINQ:
return (str ?? "").Split(',').Select<string, int>(int.Parse);
If you don't want to have the current error handling behaviour, it's really easy:
return text.Split(',').Select(x => int.Parse(x));
Otherwise, I'd use an extra helper method (as seen this morning!):
public static int? TryParseInt32(string text)
{
int value;
return int.TryParse(text, out value) ? value : (int?) null;
}
and:
return text.Split(',').Select<string, int?>(TryParseInt32)
.Where(x => x.HasValue)
.Select(x => x.Value);
or if you don't want to use the method group conversion:
return text.Split(',').Select(t => t.TryParseInt32(t)
.Where(x => x.HasValue)
.Select(x => x.Value);
or in query expression form:
return from t in text.Split(',')
select TryParseInt32(t) into x
where x.HasValue
select x.Value;
Without using a lambda function and for valid inputs only, I think it's clearer to do this:
Array.ConvertAll<string, int>(value.Split(','), Convert.ToInt32);
--EDIT-- It looks like I took his question heading too literally - he was asking for an array of ints rather than a List --EDIT ENDS--
Yet another helper method...
private static int[] StringToIntArray(string myNumbers)
{
List<int> myIntegers = new List<int>();
Array.ForEach(myNumbers.Split(",".ToCharArray()), s =>
{
int currentInt;
if (Int32.TryParse(s, out currentInt))
myIntegers.Add(currentInt);
});
return myIntegers.ToArray();
}
quick test code for it, too...
static void Main(string[] args)
{
string myNumbers = "1,2,3,4,5";
int[] myArray = StringToIntArray(myNumbers);
Console.WriteLine(myArray.Sum().ToString()); // sum is 15.
myNumbers = "1,2,3,4,5,6,bad";
myArray = StringToIntArray(myNumbers);
Console.WriteLine(myArray.Sum().ToString()); // sum is 21
Console.ReadLine();
}
Let us assume that you will be reading the string from the console. Import System.Linq and try this one:
int[] input = Console.ReadLine()
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();
This has been asked before. .Net has a built-in ConvertAll function for converting between an array of one type to an array of another type. You can combine this with Split to separate the string to an array of strings
Example function:
static int[] ToIntArray(this string value, char separator)
{
return Array.ConvertAll(value.Split(separator), s=>int.Parse(s));
}
Taken from here
This is for longs, but you can modify it easily to work with ints.
private static long[] ConvertStringArrayToLongArray(string str)
{
return str.Split(",".ToCharArray()).Select(x => long.Parse(x.ToString())).ToArray();
}
I don't see why taking out the enumerator explicitly offers you any advantage over using a foreach. There's also no need to call AsEnumerable on chunks.
import java.util.*;
import java.io.*;
public class problem
{
public static void main(String args[])enter code here
{
String line;
String[] lineVector;
int n,m,i,j;
Scanner sc = new Scanner(System.in);
line = sc.nextLine();
lineVector = line.split(",");
//enter the size of the array
n=Integer.parseInt(lineVector[0]);
m=Integer.parseInt(lineVector[1]);
int arr[][]= new int[n][m];
//enter the array here
System.out.println("Enter the array:");
for(i=0;i<n;i++)
{
line = sc.nextLine();
lineVector = line.split(",");
for(j=0;j<m;j++)
{
arr[i][j] = Integer.parseInt(lineVector[j]);
}
}
sc.close();
}
}
On the first line enter the size of the array separated by a comma. Then enter the values in the array separated by a comma.The result is stored in the array arr.
e.g
input:
2,3
1,2,3
2,4,6
will store values as
arr = {{1,2,3},{2,4,6}};
I want an efficient way of grouping strings whilst keeping duplicates and order.
Something like this
1100110002200 -> 101020
I tried this previously
_case.GroupBy(c => c).Select(g => g.Key)
but I got 102
But this gives me what I want, I just want to optimize it, so I wouldn't have to scour the entire list each time
static List<char> group(string _case)
{
var groups = new List<char>();
for (int i = 0; i < _case.Length; i++)
{
if (groups.LastOrDefault() != _case[i])
groups.Add(_case[i]);
}
return groups;
}
While I like the elegant solution of rshepp, it turns out that the very basic code can run even 5 times faster than that.
public static string Simplify2(string str)
{
if (string.IsNullOrEmpty(str)) { return str; }
StringBuilder sb = new StringBuilder();
char last = str[0];
sb.Append(last);
foreach (char c in str)
{
if (last != c)
{
sb.Append(c);
last = c;
}
}
return sb.ToString();
}
You could create a method that loops each character and checks the previous character for equality. If they aren't the same, append/yield return the character. This is pretty easy to do with Linq.
public static string Simplify(string str)
{
return string.Concat(str.Where((c, i) => i == 0 || c != str[i - 1]));
}
Usage:
string simplified = Simplify("1100110002200");
// 101020
In my testing, my method and yours are roughly equal in speed, mine being insignificantly slower after 10 million executions (4260ms vs 4241ms).
However, my method returns the result as a string whereas yours doesn't. If you need to convert your result back to a string (which is likely) then my method is indeed much faster/more efficient (4260ms vs 6569ms).
I only found a way to do it the opposite way round: create a comma separated string from an int list or array, but not on how to convert input like string str = "1,2,3,4,5"; to an array or list of ints.
Here is my implementation (inspired by this post by Eric Lippert):
public static IEnumerable<int> StringToIntList(string str)
{
if (String.IsNullOrEmpty(str))
{
yield break;
}
var chunks = str.Split(',').AsEnumerable();
using (var rator = chunks.GetEnumerator())
{
while (rator.MoveNext())
{
int i = 0;
if (Int32.TryParse(rator.Current, out i))
{
yield return i;
}
else
{
continue;
}
}
}
}
Do you think this is a good approach or is there a more easy, maybe even built in way?
EDIT: Sorry for any confusion, but the method needs to handle invalid input like "1,2,,,3" or "###, 5," etc. by skipping it.
You should use a foreach loop, like this:
public static IEnumerable<int> StringToIntList(string str) {
if (String.IsNullOrEmpty(str))
yield break;
foreach(var s in str.Split(',')) {
int num;
if (int.TryParse(s, out num))
yield return num;
}
}
Note that like your original post, this will ignore numbers that couldn't be parsed.
If you want to throw an exception if a number couldn't be parsed, you can do it much more simply using LINQ:
return (str ?? "").Split(',').Select<string, int>(int.Parse);
If you don't want to have the current error handling behaviour, it's really easy:
return text.Split(',').Select(x => int.Parse(x));
Otherwise, I'd use an extra helper method (as seen this morning!):
public static int? TryParseInt32(string text)
{
int value;
return int.TryParse(text, out value) ? value : (int?) null;
}
and:
return text.Split(',').Select<string, int?>(TryParseInt32)
.Where(x => x.HasValue)
.Select(x => x.Value);
or if you don't want to use the method group conversion:
return text.Split(',').Select(t => t.TryParseInt32(t)
.Where(x => x.HasValue)
.Select(x => x.Value);
or in query expression form:
return from t in text.Split(',')
select TryParseInt32(t) into x
where x.HasValue
select x.Value;
Without using a lambda function and for valid inputs only, I think it's clearer to do this:
Array.ConvertAll<string, int>(value.Split(','), Convert.ToInt32);
--EDIT-- It looks like I took his question heading too literally - he was asking for an array of ints rather than a List --EDIT ENDS--
Yet another helper method...
private static int[] StringToIntArray(string myNumbers)
{
List<int> myIntegers = new List<int>();
Array.ForEach(myNumbers.Split(",".ToCharArray()), s =>
{
int currentInt;
if (Int32.TryParse(s, out currentInt))
myIntegers.Add(currentInt);
});
return myIntegers.ToArray();
}
quick test code for it, too...
static void Main(string[] args)
{
string myNumbers = "1,2,3,4,5";
int[] myArray = StringToIntArray(myNumbers);
Console.WriteLine(myArray.Sum().ToString()); // sum is 15.
myNumbers = "1,2,3,4,5,6,bad";
myArray = StringToIntArray(myNumbers);
Console.WriteLine(myArray.Sum().ToString()); // sum is 21
Console.ReadLine();
}
Let us assume that you will be reading the string from the console. Import System.Linq and try this one:
int[] input = Console.ReadLine()
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();
This has been asked before. .Net has a built-in ConvertAll function for converting between an array of one type to an array of another type. You can combine this with Split to separate the string to an array of strings
Example function:
static int[] ToIntArray(this string value, char separator)
{
return Array.ConvertAll(value.Split(separator), s=>int.Parse(s));
}
Taken from here
This is for longs, but you can modify it easily to work with ints.
private static long[] ConvertStringArrayToLongArray(string str)
{
return str.Split(",".ToCharArray()).Select(x => long.Parse(x.ToString())).ToArray();
}
I don't see why taking out the enumerator explicitly offers you any advantage over using a foreach. There's also no need to call AsEnumerable on chunks.
import java.util.*;
import java.io.*;
public class problem
{
public static void main(String args[])enter code here
{
String line;
String[] lineVector;
int n,m,i,j;
Scanner sc = new Scanner(System.in);
line = sc.nextLine();
lineVector = line.split(",");
//enter the size of the array
n=Integer.parseInt(lineVector[0]);
m=Integer.parseInt(lineVector[1]);
int arr[][]= new int[n][m];
//enter the array here
System.out.println("Enter the array:");
for(i=0;i<n;i++)
{
line = sc.nextLine();
lineVector = line.split(",");
for(j=0;j<m;j++)
{
arr[i][j] = Integer.parseInt(lineVector[j]);
}
}
sc.close();
}
}
On the first line enter the size of the array separated by a comma. Then enter the values in the array separated by a comma.The result is stored in the array arr.
e.g
input:
2,3
1,2,3
2,4,6
will store values as
arr = {{1,2,3},{2,4,6}};
I need to search a string in the string array. I dont want to use any for looping in it
string [] arr = {"One","Two","Three"};
string theString = "One"
I need to check whether theString variable is present in arr.
Well, something is going to have to look, and looping is more efficient than recursion (since tail-end recursion isn't fully implemented)... so if you just don't want to loop yourself, then either of:
bool has = arr.Contains(var); // .NET 3.5
or
bool has = Array.IndexOf(arr, var) >= 0;
For info: avoid names like var - this is a keyword in C# 3.0.
Every method, mentioned earlier does looping either internally or externally, so it is not really important how to implement it. Here another example of finding all references of target string
string [] arr = {"One","Two","Three"};
var target = "One";
var results = Array.FindAll(arr, s => s.Equals(target));
Does it have to be a string[] ? A List<String> would give you what you need.
List<String> testing = new List<String>();
testing.Add("One");
testing.Add("Two");
testing.Add("Three");
testing.Add("Mouse");
bool inList = testing.Contains("Mouse");
bool exists = arr.Contains("One");
I think it is better to use Array.Exists than Array.FindAll.
Its pretty simple. I always use this code to search string from a string array
string[] stringArray = { "text1", "text2", "text3", "text4" };
string value = "text3";
int pos = Array.IndexOf(stringArray, value);
if (pos > -1)
{
return true;
}
else
{
return false;
}
If the array is sorted, you can use BinarySearch. This is a O(log n) operation, so it is faster as looping. If you need to apply multiple searches and speed is a concern, you could sort it (or a copy) before using it.
Each class implementing IList has a method Contains(Object value). And so does System.Array.
Why the prohibition "I don't want to use any looping"? That's the most obvious solution. When given the chance to be obvious, take it!
Note that calls like arr.Contains(...) are still going to loop, it just won't be you who has written the loop.
Have you considered an alternate representation that's more amenable to searching?
A good Set implementation would perform well. (HashSet, TreeSet or the local equivalent).
If you can be sure that arr is sorted, you could use binary search (which would need to recurse or loop, but not as often as a straight linear search).
You can use Find method of Array type. From .NET 3.5 and higher.
public static T Find<T>(
T[] array,
Predicate<T> match
)
Here is some examples:
// we search an array of strings for a name containing the letter “a”:
static void Main()
{
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, ContainsA);
Console.WriteLine (match); // Jack
}
static bool ContainsA (string name) { return name.Contains ("a"); }
Here’s the same code shortened with an anonymous method:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, delegate (string name)
{ return name.Contains ("a"); } ); // Jack
A lambda expression shortens it further:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, n => n.Contains ("a")); // Jack
At first shot, I could come up with something like this (but it's pseudo code and assuming you cannot use any .NET built-in libaries). Might require a bit of tweaking and re-thinking, but should be good enough for a head-start, maybe?
int findString(String var, String[] stringArray, int currentIndex, int stringMaxIndex)
{
if currentIndex > stringMaxIndex
return (-stringMaxIndex-1);
else if var==arr[currentIndex] //or use any string comparison op or function
return 0;
else
return findString(var, stringArray, currentIndex++, stringMaxIndex) + 1 ;
}
//calling code
int index = findString(var, arr, 0, getMaxIndex(arr));
if index == -1 printOnScreen("Not found");
else printOnScreen("Found on index: " + index);
In C#, if you can use an ArrayList, you can use the Contains method, which returns a boolean:
if MyArrayList.Contains("One")
You can check the element existence by
arr.Any(x => x == "One")
it is old one ,but this is the way i do it ,
enter code herevar result = Array.Find(names, element => element == "One");
I'm surprised that no one suggested using Array.IndexOf Method.
Indeed, Array.IndexOf has two advantages :
It allows searching if an element is included into an array,
It gets at the same time the index into the array.
int stringIndex = Array.IndexOf(arr, theString);
if (stringIndex >= 0)
{
// theString has been found
}
Inline version :
if (Array.IndexOf(arr, theString) >= 0)
{
// theString has been found
}
Using Contains()
string [] SomeArray = {"One","Two","Three"};
bool IsExist = SomeArray.Contains("One");
Console.WriteLine("Is string exist: "+ IsExist);
Using Find()
string [] SomeArray = {"One","Two","Three"};
var result = Array.Find(SomeArray, element => element == "One");
Console.WriteLine("Required string is: "+ result);
Another simple & traditional way, very useful for beginners to build logic.
string [] SomeArray = {"One","Two","Three"};
foreach (string value in SomeArray) {
if (value == "One") {
Console.WriteLine("Required string is: "+ value);
}
}
I need a list of integers from 1 to x where x is set by the user. I could build it with a for loop eg assuming x is an integer set previously:
List<int> iList = new List<int>();
for (int i = 1; i <= x; i++)
{
iList.Add(i);
}
This seems dumb, surely there's a more elegant way to do this, something like the PHP range method
If you're using .Net 3.5, Enumerable.Range is what you need.
Generates a sequence of integral
numbers within a specified range.
LINQ to the rescue:
// Adding value to existing list
var list = new List<int>();
list.AddRange(Enumerable.Range(1, x));
// Creating new list
var list = Enumerable.Range(1, x).ToList();
See Generation Operators on LINQ 101
I'm one of many who has blogged about a ruby-esque To extension method that you can write if you're using C#3.0:
public static class IntegerExtensions
{
public static IEnumerable<int> To(this int first, int last)
{
for (int i = first; i <= last; i++)
{
yield return i;
}
}
}
Then you can create your list of integers like this
List<int> = first.To(last).ToList();
or
List<int> = 1.To(x).ToList();
Here is a short method that returns a List of integers.
public static List<int> MakeSequence(int startingValue, int sequenceLength)
{
return Enumerable.Range(startingValue, sequenceLength).ToList<int>();
}