Refactoring with Lambda's and Delegates - c#

I've just installed VS2008 and have run into a problem that I'm sure can be solved with either lambda's or delegates (or a combination!).
private string ReadData(TcpClient s, string terminator)
{
// Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
var sb = new StringBuilder();
do
{
var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
} while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminator));
return sb.ToString();
}
The problem is, sometimes I need to check if the string contains either of two different values. Sometimes I may need to check it for three values.
So what I propose, is to change " !sb.ToString().Contains(terminator)" to a function that is passed into the method.
I could write my different functions such as:
private bool compare1(string s, string t) {
return s.contains(t)
}
private bool compare2(string s, string t1, string t2) {
return (s.compare(t1) or s.compare(t2)
}
// etc...
Then when I want to compare with 3 different values, create a delegate to one of these functions, then pass that to the ReadData() method.
I'm very clueless when it comes to delegates, and I'm not sure if this seems like the right place for a lambda but something is telling me it is.
The calling code is this:
// Enter username .
if (HasData(s,"login:"))
SendData(s, switchUser + TelnetHelper.CRLF);
HasData is identical to ReadData, but returns a bool instead of a string (which I'd also like to factor out into one method using some trickery - but that's a secondary question - feel free to answer that though.
Just for reference:
private bool HasData(TcpClient s, string terminator)
{
// Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
var sb = new StringBuilder();
do
{
var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
} while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminator));
return sb.ToString().Contains(terminator);
}

It sounds like you're looking for a predicate function. Instead of hard coding the check, take a delegate as a parameter than can do the check
private string ReadData(TcpClient s, Func<string,bool> predicate)
{
// Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
var sb = new StringBuilder();
do
{
var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
} while (s.GetStream().DataAvailable && !predicate(sb));
return sb.ToString();
}
Then you can create several wrappers which just create the appropriate delegate and pass it down
public bool HasData(TcpClient c, string terminator) {
return HasData(c, (s) => s.Contains(terminator));
}
public bool HasData(TcpClient c, string t1, string t2) {
return HasData(c, (s) => s.Contains(t1) || s.Contains(t2));
}
You can even build a delegate on the fly based on arbitrary number of terminators
public bool HasData(TcpClient c, params string[] terminatorList) {
return HasData(c, (s) => terminatorList.Where(x => s.Contains(x)).Any());
}

One option would be to overload the ReadData() method to take a string array containing the values that you are checking for. Using an extension method, you could extend Contains() to take a string array.
Your ReadData() method could be:
private string ReadData(TcpClient s, string[] terminators) {
// Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
var sb = new StringBuilder();
do
{
var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
} while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminators));
return sb.ToString();
}
The Contains() method extension could be:
public static bool Contains ( this String str , String[] testValues )
{
foreach ( var value in testValues )
{
if ( str.Contains( value ) )
return true;
}
return false;
}
This implementation eliminates the need to create a new predicate each time you have a different number of strings to test for.

Because the syntax of the lambdas is somewhat foreign to myself (and the rest of my team) I ended up going with a slightly different solution. I couldn't figure out the syntax of .All() when modified from the .Any() function above.
I needed an .All() function as well, to ensure all the terminators in the list were found. So I ended up going with something like the following:
delegate bool Predicate (string s, params [] string terminators);
bool HasAll(string s, params string [] terminators) {
foreach (var t in terminators) {
if (!s.contains(t)) return false;
}
return true;
}
bool HasAny(string s, params string [] terminators) {
foreach (var t in terminators) {
if (s.contains(t)) return true;
}
return false;
}
// Just looking now, I could also pass in a bool to switch between the two and remove one of these functions. But this is fairly clear
string ReadData(TcpClient sock, Function predicate, params [] string terminators) {
var sb = new StringBuilder();
do
{
var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
} while (s.GetStream().DataAvailable && !predicate(sb.ToString(), terminators);
return sb.ToString();
}
Then the calling code looks like:
private void someFunc()
{
Predicate any = new Predicate(HasAny);
Predicate all = new Predicate(HasAll);
String response;
// Check all strings exist
response = ReadData(this.sock, all, "(", ")", "->")
if (all(response, "(", ")", "->")
SendData(this.sock, ...);
// Check any string exists
response = ReadData(this.sock, any, "Hi", "Hey", "Hello");
if (any(response, "Hi", "Hey", "Hello"))
SendData(this.sock, ...);
}
I'll probably add null checks into the Has[Any|All] functions, reverse the do..while to a while, and just check response != null instead of duplicating the params. This solutions suits all my use cases and is fairly human readable I think. As long as I make the small changes I mentioned just above.
This whole thing highlights for me my need to learn lambda expressions though!

Related

substring out of range

I am trying to extract the number out of the last part of the string, I have wrote a function to do this but am having problems with out of range index.
Here is the string
type="value" cat=".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.1" descCat=".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3"
and here is my function
private static string ExtractDescOID(string property)
{
string result = "";
int startPos = property.LastIndexOf("descOid=\"") + "descOid=\"".Length;
int endPos = property.Length - 1;
if (endPos - startPos != 1)
{
//This now gets rid of the first . within the string.
startPos++;
result = property.Substring(startPos, endPos);
}
else
{
result = "";
}
if (startPos == endPos)
{
Console.WriteLine("Something has gone wrong");
}
return result;
}
I want to be able to get 1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3 this part of the string. I have stepped through the code, the string length is 99 however when AND MY startPos becomes 64 and endPos becomes 98 which is actually within the range.
The second argument to Substring(int, int) isn't the "end position", but the length of the substring to return.
result = property.Substring(startPos, endPos - startPos);
Read the documentation again, the second value is the length, not the index.
As found on MSDN:
public string Substring(
int startIndex,
int length
)
A different approach to this problem could be through using string.Split() to take care of the parsing for you. The only reason why I would propose this (other than that I like to present additional options to what's already there, plus this is the lazy man's way out) is that from a code perspective, the code is easier IMHO to decompose, and when decomposed, is easier to comprehend by others.
Here's the sample program with some comments to illustrate my point (tested, btw).
class Program
{
static void Main(string[] args)
{
var someAttributesFromAnXmlNodeIGuess =
"type=\"value\" cat=\".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.1\" descCat=\".1.3.6.1.4.1.26928.1.1.1.2.1.2.1.3\"";
var descCat = GetMeTheAttrib(someAttributesFromAnXmlNodeIGuess, "descCat");
Console.WriteLine(descCat);
Console.ReadLine();
}
// making the slightly huge assumption that you may want to
// access other attribs in the string...
private static string GetMeTheAttrib(string attribLine, string attribName)
{
var parsedDictionary = ParseAttributes(attribLine);
if (parsedDictionary.ContainsKey(attribName))
{
return parsedDictionary[attribName];
}
return string.Empty;
}
// keeping the contracts simple -
// i could have used IDictionary, which might make sense
// if this code became LINQ'd one day
private static Dictionary<string, string> ParseAttributes(string attribLine)
{
var dictionaryToReturn = new Dictionary<string, string>();
var listOfPairs = attribLine.Split(' '); // items look like type=value, etc
foreach (var pair in listOfPairs)
{
var attribList = pair.Split('=');
// we were expecting a type=value pattern... if this doesn't match then let's ignore it
if (attribList.Count() != 2) continue;
dictionaryToReturn.Add(attribList[0], attribList[1]);
}
return dictionaryToReturn;
}
}

how to compare 2 strings in c#

I have some string like this:
str1 = STA001, str2 = STA002, str3 = STA003
and have code to compare strings:
private bool IsSubstring(string strChild, string strParent)
{
if (!strParent.Contains(strChild))
{
return false;
}
else return true;
}
If I have strChild = STA001STA002 and strParent = STA001STA002STA003 then return true but when I enter strChild = STA001STA003 and check with strParent = STA001STA002STA003 then return false although STA001STA003 have contains in strParent. How can i resolve it?
What you're describing is not a substring. It is basically asking of two collections the question "is this one a subset of the other one?" This question is far easier to ask when the collection is a set such as HashSet<T> than when the collection is a big concatenated string.
This would be a much better way to write your code:
var setOne = new HashSet<string> { "STA001", "STA003" };
var setTwo = new HashSet<string> { "STA001", "STA002", "STA003" };
Console.WriteLine(setOne.IsSubsetOf(setTwo)); // True
Console.WriteLine(setTwo.IsSubsetOf(setOne)); // False
Or, if the STA00 part was just filler to make it make sense in the context of strings, then use ints directly:
var setOne = new HashSet<int> { 1, 3 };
var setTwo = new HashSet<int> { 1, 2, 3 };
Console.WriteLine(setOne.IsSubsetOf(setTwo)); // True
Console.WriteLine(setTwo.IsSubsetOf(setOne)); // False
The Contains method only looks for an exact match, it doesn't look for parts of the string.
Divide the child string into its parts, and look for each part in the parent string:
private bool IsSubstring(string child, string parent) {
for (int i = 0; i < child.Length; i+= 6) {
if (!parent.Contains(child.Substring(i, 6))) {
return false;
}
}
return true;
}
You should however consider it cross-part matches are possible, and if that is an issue. E.g. looking for "1STA00" in "STA001STA002". If that would be a problem, then you should divide the parent string similarly, and only make direct comparisons between the parts, not using the Contains method.
Note: Using hungarian notation for the data type of variables is not encouraged in C#.
This may be a bit on the overkill side, but it might be incredibly beneficial.
private static bool ContainedWord(string input, string phrase)
{
var pattern = String.Format(#"\b({0})", phrase);
var result = Regex.Match(input, pattern);
if(string.Compare(result, phrase) == 0)
return true;
return false;
}
If the expression finds a match, then compare the result to your phrase. If they're zero, it matched. I may be misunderstanding your intent.

Check if a String is combined with Several Substring in C#

Lets say I have several short string:
string[] shortStrings = new string[] {"xxx","yyy","zzz"};
(this definition can change length on array and on string too, so not a fixed one)
When a given string, I like to check if it combines with the shortStrings ONLY, how?
let say function is like bool TestStringFromShortStrings(string s)
then
TestStringFromShortStrings("xxxyyyzzz") = true;
TestStringFromShortStrings("xxxyyyxxx") = true;
TestStringFromShortStrings("xxxyyy") = true;
TestStringFromShortStrings("xxxxxx") = true;
TestStringFromShortStrings("xxxxx") = false;
TestStringFromShortStrings("xxxXyyyzzz") = false;
TestStringFromShortStrings("xxx2yyyxxx") = false;
Please suggest a memory not tense and relatively fast method.
[EIDT] What this function for?
I will personally use this function to test if a string is a combination of a PINYIN ok, some Chinese stuff. Following Chinese are same thing if you cannot read it.
检测一个字符串是否为汉语拼音(例如检测是否拼音域名)
所有的汉语拼音字符串有:
(To detect whether a string is Hanyu Pinyin (e.g. detect the phonetic domain) of the Pinyin string:)
Regex PinYin = new Regex(#"^(a|ai|an|ang|ao|ba|bai|ban|bang|bao|bei|ben|beng|bi|bian|biao|bie|bin|bing|bo|bu|ca|cai|can|cang|cao|ce|cen|ceng|cha|chai|chan|chang|chao|che|chen|cheng|chi|chong|chou|chu|chua|chuai|chuan|chuang|chui|chun|chuo|ci|cong|cou|cu|cuan|cui|cun|cuo|da|dai|dan|dang|dao|de|den|dei|deng|di|dia|dian|diao|die|ding|diu|dong|dou|du|duan|dui|dun|duo|e|ei|en|eng|er|fa|fan|fang|fei|fen|feng|fo|fou|fu|ga|gai|gan|gang|gao|ge|gei|gen|geng|gong|gou|gu|gua|guai|guan|guang|gui|gun|guo|ha|hai|han|hang|hao|he|hei|hen|heng|hong|hou|hu|hua|huai|huan|huang|hui|hun|huo|ji|jia|jian|jiang|jiao|jie|jin|jing|jiong|jiu|ju|juan|jue|jun|ka|kai|kan|kang|kao|ke|ken|keng|kong|kou|ku|kua|kuai|kuan|kuang|kui|kun|kuo|la|lai|lan|lang|lao|le|lei|leng|li|lia|lian|liang|liao|lie|lin|ling|liu|long|lou|lu|lv|luan|lue|lve|lun|luo|ma|mai|man|mang|mao|me|mei|men|meng|mi|mian|miao|mie|min|ming|miu|mo|mou|mu|na|nai|nan|nang|nao|ne|nei|nen|neng|ni|nian|niang|niao|nie|nin|ning|niu|nong|nou|nu|nv|nuan|nuo|nun|ou|pa|pai|pan|pang|pao|pei|pen|peng|pi|pian|piao|pie|pin|ping|po|pou|pu|qi|qia|qian|qiang|qiao|qie|qin|qing|qiong|qiu|qu|quan|que|qun|ran|rang|rao|re|ren|reng|ri|rong|rou|ru|ruan|rui|run|ruo|sa|sai|san|sang|sao|se|sen|seng|sha|shai|shan|shang|shao|she|shei|shen|sheng|shi|shou|shu|shua|shuai|shuan|shuang|shui|shun|shuo|si|song|sou|su|suan|sui|sun|suo|ta|tai|tan|tang|tao|te|teng|ti|tian|tiao|tie|ting|tong|tou|tu|tuan|tui|tun|tuo|wa|wai|wan|wang|wei|wen|weng|wo|wu|xi|xia|xian|xiang|xiao|xie|xin|xing|xiong|xiu|xu|xuan|xue|xun|ya|yan|yang|yao|ye|yi|yin|ying|yo|yong|you|yu|yuan|yue|yun|za|zai|zan|zang|zao|ze|zei|zen|zeng|zha|zhai|zhan|zhang|zhao|zhe|zhei|zhen|zheng|zhi|zhong|zhou|zhu|zhua|zhuai|zhuan|zhuang|zhui|zhun|zhuo|zi|zong|zou|zu|zuan|zui|zun|zuo)+$");
用下面的正则表达式方法,试过了,最简单而且效果非常好,就是有点慢:(
递归的方式对长字符串比较麻烦,容易内存溢出
(Tried it with the regular expression: it's the most simple and gives very good results, but it's a bit slow. The recursive way on the long string is too much trouble, it's too easy to overflow the stack.)
Edit: Simplified this a lot thanks to L.B and millimoose.
Regular Expressions to the rescue! Using System.Text.RegularExpressions.Regex, we get:
public static bool TestStringFromShortStrings(string checkText, string[] pieces) {
// Build the expression. Ultimate result will be
// of the form "^(xxx|yyy|zzz)+$".
var expr = "^(" +
String.Join("|", pieces.Select(Regex.Escape)) +
")+$";
// Check whether the supplied string matches the expression.
return Regex.IsMatch(checkText, expr);
}
This should be able to properly handle cases that have multiple repeated patterns of different lenghts. E.g. if you the list of possible pieces includes strings "xxx" and "xxxx".
Copy the target string to string builder. For each string in shortstring array, remove all occurences from target. If u end up in zero length string, true else false.
Edit:
This approach is not correct. Please refer to comments. Keeping this answer still here as it may look reasonably correct initially.
You could compare the start of the input string with each of the short strings. As soon as you have a match, you take the rest of the string and repeat. As soon as you have no more string left, you're done. For example:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
if (input.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (input.StartsWith(shortStr))
{
if (Test(input.Substring(shortStr.Length)))
return true;
}
}
return false;
}
You might optimize this by removing the recursion, or by sorting the short strings and do a binary instead of a linear search.
Here is a non-recursive version, that uses a Stack object instead. No chance of getting a StackOverflowException:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
Stack<string> stack = new Stack<string>();
stack.Push(input);
while (stack.Count > 0)
{
string str = stack.Pop();
if (str.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (str.StartsWith(shortStr))
stack.Push(str.Substring(shortStr.Length));
}
}
return false;
}

int array to string

In C#, I have an array of ints, containing digits only. I want to convert this array to string.
Array example:
int[] arr = {0,1,2,3,0,1};
How can I convert this to a string formatted as: "012301"?
at.net 3.5 use:
String.Join("", new List<int>(array).ConvertAll(i => i.ToString()).ToArray());
at.net 4.0 or above use: (see #Jan Remunda's answer)
string result = string.Join("", array);
You can simply use String.Join function, and as separator use string.Empty because it uses StringBuilder internally.
string result = string.Join(string.Empty, new []{0,1,2,3,0,1});
E.g.: If you use semicolon as separator, the result would be 0;1;2;3;0;1.
It actually works with null separator, and second parameter can be enumerable of any objects, like:
string result = string.Join(null, new object[]{0,1,2,3,0,"A",DateTime.Now});
I realize my opinion is probably not the popular one, but I guess I have a hard time jumping on the Linq-y band wagon. It's nifty. It's condensed. I get that and I'm not opposed to using it where it's appropriate. Maybe it's just me, but I feel like people have stopped thinking about creating utility functions to accomplish what they want and instead prefer to litter their code with (sometimes) excessively long lines of Linq code for the sake of creating a dense 1-liner.
I'm not saying that any of the Linq answers that people have provided here are bad, but I guess I feel like there is the potential that these single lines of code can start to grow longer and more obscure as you need to handle various situations. What if your array is null? What if you want a delimited string instead of just purely concatenated? What if some of the integers in your array are double-digit and you want to pad each value with leading zeros so that the string for each element is the same length as the rest?
Taking one of the provided answers as an example:
result = arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
If I need to worry about the array being null, now it becomes this:
result = (arr == null) ? null : arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
If I want a comma-delimited string, now it becomes this:
result = (arr == null) ? null : arr.Skip(1).Aggregate(arr[0].ToString(), (s, i) => s + "," + i.ToString());
This is still not too bad, but I think it's not obvious at a glance what this line of code is doing.
Of course, there's nothing stopping you from throwing this line of code into your own utility function so that you don't have that long mess mixed in with your application logic, especially if you're doing it in multiple places:
public static string ToStringLinqy<T>(this T[] array, string delimiter)
{
// edit: let's replace this with a "better" version using a StringBuilder
//return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(array[0].ToString(), (s, i) => s + "," + i.ToString());
return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(new StringBuilder(array[0].ToString()), (s, i) => s.Append(delimiter).Append(i), s => s.ToString());
}
But if you're going to put it into a utility function anyway, do you really need it to be condensed down into a 1-liner? In that case why not throw in a few extra lines for clarity and take advantage of a StringBuilder so that you're not doing repeated concatenation operations:
public static string ToStringNonLinqy<T>(this T[] array, string delimiter)
{
if (array != null)
{
// edit: replaced my previous implementation to use StringBuilder
if (array.Length > 0)
{
StringBuilder builder = new StringBuilder();
builder.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
builder.Append(delimiter);
builder.Append(array[i]);
}
return builder.ToString()
}
else
{
return string.Empty;
}
}
else
{
return null;
}
}
And if you're really so concerned about performance, you could even turn it into a hybrid function that decides whether to do string.Join or to use a StringBuilder depending on how many elements are in the array (this is a micro-optimization, not worth doing in my opinion and possibly more harmful than beneficial, but I'm using it as an example for this problem):
public static string ToString<T>(this T[] array, string delimiter)
{
if (array != null)
{
// determine if the length of the array is greater than the performance threshold for using a stringbuilder
// 10 is just an arbitrary threshold value I've chosen
if (array.Length < 10)
{
// assumption is that for arrays of less than 10 elements
// this code would be more efficient than a StringBuilder.
// Note: this is a crazy/pointless micro-optimization. Don't do this.
string[] values = new string[array.Length];
for (int i = 0; i < values.Length; i++)
values[i] = array[i].ToString();
return string.Join(delimiter, values);
}
else
{
// for arrays of length 10 or longer, use a StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
sb.Append(delimiter);
sb.Append(array[i]);
}
return sb.ToString();
}
}
else
{
return null;
}
}
For this example, the performance impact is probably not worth caring about, but the point is that if you are in a situation where you actually do need to be concerned with the performance of your operations, whatever they are, then it will most likely be easier and more readable to handle that within a utility function than using a complex Linq expression.
That utility function still looks kind of clunky. Now let's ditch the hybrid stuff and do this:
// convert an enumeration of one type into an enumeration of another type
public static IEnumerable<TOut> Convert<TIn, TOut>(this IEnumerable<TIn> input, Func<TIn, TOut> conversion)
{
foreach (TIn value in input)
{
yield return conversion(value);
}
}
// concatenate the strings in an enumeration separated by the specified delimiter
public static string Delimit<T>(this IEnumerable<T> input, string delimiter)
{
IEnumerator<T> enumerator = input.GetEnumerator();
if (enumerator.MoveNext())
{
StringBuilder builder = new StringBuilder();
// start off with the first element
builder.Append(enumerator.Current);
// append the remaining elements separated by the delimiter
while (enumerator.MoveNext())
{
builder.Append(delimiter);
builder.Append(enumerator.Current);
}
return builder.ToString();
}
else
{
return string.Empty;
}
}
// concatenate all elements
public static string ToString<T>(this IEnumerable<T> input)
{
return ToString(input, string.Empty);
}
// concatenate all elements separated by a delimiter
public static string ToString<T>(this IEnumerable<T> input, string delimiter)
{
return input.Delimit(delimiter);
}
// concatenate all elements, each one left-padded to a minimum length
public static string ToString<T>(this IEnumerable<T> input, int minLength, char paddingChar)
{
return input.Convert(i => i.ToString().PadLeft(minLength, paddingChar)).Delimit(string.Empty);
}
Now we have separate and fairly compact utility functions, each of which are arguable useful on their own.
Ultimately, my point is not that you shouldn't use Linq, but rather just to say don't forget about the benefits of creating your own utility functions, even if they are small and perhaps only contain a single line that returns the result from a line of Linq code. If nothing else, you'll be able to keep your application code even more condensed than you could achieve with a line of Linq code, and if you are using it in multiple places, then using a utility function makes it easier to adjust your output in case you need to change it later.
For this problem, I'd rather just write something like this in my application code:
int[] arr = { 0, 1, 2, 3, 0, 1 };
// 012301
result = arr.ToString<int>();
// comma-separated values
// 0,1,2,3,0,1
result = arr.ToString(",");
// left-padded to 2 digits
// 000102030001
result = arr.ToString(2, '0');
To avoid the creation of an extra array you could do the following.
var builder = new StringBuilder();
Array.ForEach(arr, x => builder.Append(x));
var res = builder.ToString();
string result = arr.Aggregate("", (s, i) => s + i.ToString());
(Disclaimer: If you have a lot of digits (hundreds, at least) and you care about performance, I suggest eschewing this method and using a StringBuilder, as in JaredPar's answer.)
You can do:
int[] arr = {0,1,2,3,0,1};
string results = string.Join("",arr.Select(i => i.ToString()).ToArray());
That gives you your results.
I like using StringBuilder with Aggregate(). The "trick" is that Append() returns the StringBuilder instance itself:
var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
var result = sb.ToString();
string.Join("", (from i in arr select i.ToString()).ToArray())
In the .NET 4.0 the string.Join can use an IEnumerable<string> directly:
string.Join("", from i in arr select i.ToString())
I've left this here for posterity but don't recommend its use as it's not terribly readable. This is especially true now that I've come back to see if after a period of some time and have wondered what I was thinking when I wrote it (I was probably thinking 'crap, must get this written before someone else posts an answer'.)
string s = string.Concat(arr.Cast<object>().ToArray());
The most efficient way is not to convert each int into a string, but rather create one string out of an array of chars. Then the garbage collector only has one new temp object to worry about.
int[] arr = {0,1,2,3,0,1};
string result = new string(Array.ConvertAll<int,char>(arr, x => Convert.ToChar(x + '0')));
This is a roundabout way to go about it its not much code and easy for beginners to understand
int[] arr = {0,1,2,3,0,1};
string joined = "";
foreach(int i in arr){
joined += i.ToString();
}
int number = int.Parse(joined);
If this is long array you could use
var sb = arr.Aggregate(new StringBuilder(), ( s, i ) => s.Append( i ), s.ToString());
// This is the original array
int[] nums = {1, 2, 3};
// This is an empty string we will end up with
string numbers = "";
// iterate on every char in the array
foreach (var item in nums)
{
// add the char to the empty string
numbers += Convert.ToString(item);
}
// Write the string in the console
Console.WriteLine(numbers);

Remove the static int from this MatchEvaluator

I'm trying to convert a proprietary string mask to the .net equivalent of it.
For that I need to exchange every occurance of [someText] with {aDigit}.
private static int hits = 0;
private static object hitsLock = new object();
public static string ConvertSdsFileMaskToStringMask(string sdsFileMaskString) {
Regex bracketsExpression = new Regex(#"\[[^[]*]");
lock (hitsLock)
{
hits = 0;
return bracketsExpression.Replace(sdsFileMaskString, ReplaceSquareWithAngularBrackets);
}
}
private static string ReplaceSquareWithAngularBrackets(Match m) {
string result = String.Format("{{{0}}}", hits.ToString());
hits++;
return result;
}
It works. But both expressions need to know each other's workings and are depending on the hits counter. I feel this could be improved. Ideally both have no dependency on each other. Any suggestions?
This can probably be done better. Any suggestions?
Yes - use an anonymous method or lambda expression:
public static string ConvertSdsFileMaskToStringMask(string sdsFileMaskString)
{
Regex bracketsExpression = new Regex(#"\[[^[]*]");
int hits = 0;
return bracketsExpression.Replace(sdsFileMaskString, match =>
{
string result = String.Format("{{{0}}}", hits.ToString());
hits++;
return result;
});
}
This will capture the local variable in a new (compiler-generated) type, getting rid of the "globalness".
If you're happy with side-effects, you could make the lambda expression simpler, too. I'd also get rid of the call to String.Format in this case, as all those braces are confusing:
public static string ConvertSdsFileMaskToStringMask(string sdsFileMaskString)
{
Regex bracketsExpression = new Regex(#"\[[^[]*]");
int hits = 0;
return bracketsExpression.Replace(sdsFileMaskString,
match => "{" + (hits++) + "}");
}
By using a lambda, and a local variable hits, C# will create a closure :
public static string ConvertSdsFileMaskToStringMask(string sdsFileMaskString)
{
Regex bracketsExpression = new Regex(#"\[[^[]*]");
int hits = 0;
return bracketsExpression.Replace(sdsFileMaskString,
m => string.Format("{{{0}}}", hits++));
}
will be sufficient
The hits variable is encapsulated in the lambda closure and will be reused inside all lambda calls, but will be distinct for several ConvertSdsFileMaskToStringMask calls.

Categories

Resources