Related
I am new to delegates. Today I saw a code on this Link. AS i am new to c# and specially to delegates, i was unable to understand the below code.
public static void Main()
{
Func<String, int, bool> predicate = (str, index) => str.Length == index;
String[] words = { "orange", "apple", "Article", "elephant", "star", "and" };
IEnumerable<String> aWords = words.Where(predicate).Select(str => str);
foreach (String word in aWords)
Console.WriteLine(word);
}
The OutPut of the above code is "star". AS predicate is expecting to parameters but in this case we are not passing any parameters. Your comments will be really appreciated.
So first, there's a function definition:
Func<String, int, bool> predicate = (str, index) => str.Length == index;
which reads as "given a string represented as str and an index represented as index return true if the length of the string is equal to the index otherwise false"
When you come across to the enumerable pipeline:
IEnumerable<String> aWords = words.Where(predicate).Select(str => str);
you pass this function definition above, which is similar to:
words.Where((element, index) => element.Length == index).Select(str => str);
and as you can see only the element "star" meets that criteria, i.e. the "star" has length 4 and its index is also 4.
In regard to your confusion of:
AS predicate is expecting to parameters but in this case we are not
passing any parameters.
Note that when it comes to LINQ, we only specify the "what" and the "how" is an implementation detail. so in the aforementioned code, the Where clause will pass each element and its index to the predicate function.
On another note, the Select is superfluous, just IEnumerable<String> aWords = words.Where(predicate) should shuffice.
Let's start to examine this code from the first line.
Func<String, int, bool> predicate = (str, index) => str.Length == index;
Here we have simply the declaration of a variable named predicate This is a particular kind of variable whose value is a function that receives two parameters of type string and int and it is expected to return a bool. But where is the body of that function? Just after the equals sign. The (str,index) are the parameters and the body is simply a comparison between the length of the parameter str with the value of the parameter index.
=> str.Length == index returns true if the condition matches otherwise returns false
Now that we understand the declaration of the delegate, the next question is where we use it. This is even simpler. We can use it whenever we need a function that matches our delegate.
Now there is an overload of Where IEnumerable extension that expects just that, so we can simply put the predicate variable in that place and call the Where extension
In short, the code just says, "Select all words where the length equals index"
string[] words = { "orange", "apple", "Article", "elephant", "star", "and" };
// select all words where the length equals the index
var aWords = words.Where((str, i) => str.Length == i);
foreach (var word in aWords)
Console.WriteLine(word);
Where<TSource>(IEnumerable<TSource>, Func<TSource,Int32,Boolean>)
Filters a sequence of values based on a predicate. Each element's
index is used in the logic of the predicate function.
Func<T1,T2,TResult> Delegate
Encapsulates a method that has two parameters and returns a value of
the type specified by the TResult parameter.
So the only magic is the Func
Func<String, int, bool> predicate = (str, index) => str.Length == index;
Which (in this case) is just a fancy way of writing
public bool DoSomething(string str, int index)
{
return str.Length == index;
}
In essence its just a delegate, unlike an Action its capable of returning a value
Delegates (C# Programming Guide)
A delegate is a type that represents references to methods with a
particular parameter list and return type. When you instantiate a
delegate, you can associate its instance with any method with a
compatible signature and return type. You can invoke (or call) the
method through the delegate instance.
To simplify it a bit,
var aWords = words.Where(str => str.Length == 4);
is the same as:
Func<string, bool> predicate = str => str.Length == 4;
var aWords = words.Where(predicate);
predicate() executes it, and predicate without () can be used to pass it as parameter to a method.
With local functions (functions that can be declared inside other functions) introduced in C# 7, it can be :
bool predicate(string str) { return str.Length == 4; }
var aWords = words.Where(predicate);
I have this function:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return iterable.Distinct();
}
This works with any IEnumerable except with a string, I must test it with this call:
Assert.AreEqual("ABCDAB", UniqueInOrder("AAAABBBCCDAABBB"));
The assert fail:
Expected is <System.String>, actual is <System.Linq.Enumerable+<DistinctIterator>c__Iterator10`1[System.Char]>
Values differ at index [4]
I also tried something like:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return "abc";
}
But I have a compiler error:
Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable<T>'
How is possible that I can call the function with a string but I can not return a string? The type is still the same IEnumerable< T >
Any idea?
Thank you!
EDITED:
Distinct() was wrong, I changed to this:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
List<T> result = new List<T>();
foreach (var c in iterable.ToList())
if (result.LastOrDefault() == null || !result.LastOrDefault().Equals(c))
result.Add(c);
return result;
}
Now all the tests are passing! Thanks!
Actually a string is a collection of characters, thus when you use UniqueInOrder("AAAABBBCCDAABBB") you actuall call UniqueInOrder<char>, instead of UniqueInOrder<string>. Thus the return-value of the method will also be IEnumerble<char>, not just string.
So you should compare the methods return-value with a collection of characters, e.g.:
CollectionAssert.AreEqual(new[] { 'A', 'B', 'C', 'D', 'A' 'B', 'Ä' }, UniqueInOrder(...));
or easier:
CollectionAssert.AreEqual(expected.ToCharArray(), UniqueInOrder(...));
But even then your test will fail as Distinct will filter out all duplicates.
When you want to check if two sequences are completely identical you may use SequenceEqual instead:
var equal = firstColl.SequenceEqual(second);
EDIT: Obviously you´re trying to remove all just the doubled characters in a sequence. You may use this:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) where T : IEquatable<T>
{
T previous = default(T);
foreach (var t in iterable)
{
if (!t.Equals(previous))
yield return t;
previous = t;
}
}
Now you can call it and compare it with your expected output, e.g.:
var actual = new String(UniqueInOrder("AABBCCDDAABB").ToArray());
var expected "ABCDAB";
Assert.AreEqual(expected, actual);
Himbrombeere has explained why the assertion fails because of the type issue. But it will also fail because Distinct does not what you expect. It will remove all duplicate letters, not only those which are consecutive. So it will return ABCD instead of ABCDAB.
This will do what you want and the assertion will pass:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable, EqualityComparer<T> comparer = null)
{
if (comparer == null) comparer = EqualityComparer<T>.Default;
bool first = true;
T lastItem = default(T);
foreach(T thisItem in iterable)
{
if (first || !comparer.Equals(thisItem, lastItem))
{
first = false;
yield return thisItem;
}
lastItem = thisItem;
}
}
Assert.AreEqual("ABCDAB", String.Conat(UniqueInOrder("AAAABBBCCDAABBB")));
As to the first part of your question, the reason your assertion is failing is because of the .Distinct()
When calling
UniqueInOrder("AAAABBBCCDAABBB");
This method:
private IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return iterable.Distinct();
}
will return {'A', 'B', 'C', 'D'}
However this method:
private IEnumerable<T> RemovesDupesInOrder<T>(IEnumerable<T> iterable)
{
List<T> result = new List<T>();
T last = default(T);
iterable.ToList().ForEach(t =>
{
if (t.Equals(last) == false)
{
last = t;
result.Add(t);
}
});
return result;
}
would return {'A', 'B', 'C', 'D', 'A', 'B'}
BEWARE: t.Equals(last) may or may not do what you expect with reference types.
UniqueInOrder("AAAABBBCCDAABBB") returns "ABCD", as these are the distinct characters in the string. This is not equal to "ABCDAB", and the difference is in the 5th character (or character 4 in code terms, since am IEnumerable is 0-indexed).
This is exactly what the assert fail is telling you. The characters differ at the element in the enumerable with index 4. Specifically, in the second argument that index doesn't exist. Assert.AreEqual("ABCD", UniqueInOrder("AAAABBBCCDAABBB")) will work fine
You get a compiler error in the return "abc" case because "abc", a string, is not a generic IEnumerable. If you passed in an IEnumerable<int> the types would be incompatible so it has to be a compiler error
I am attempting to create a parse function that takes in a string and returns an array. So far I am having a problem with my array declaration:
var sArray = sfunctions.ParseThis(ctrlValue);
ctrlValue = sArray[0]; // Get the first string from the array
rValue = sNew[1];
I have also tried:
string [] sArray = sfunctions.ParseThis(ctrlValue);
In my old c programming days I could declare an array and it would live outside a function without passing anything but a reference, just not sure how to do that in c# or coded ui test.
Thanks for assistance.
control.ClickCustomControl(parent, "InnerText", "Register-16");
where ctrlValue = "Register-16"
And - other answers:
public Array ParseThis(string sToParse)
{
char cSplit = '-';
string[] sNew = sToParse.Split(new char[] { cSplit });
return sNew;
}
If your ParseThis method must return an Array, you should then call sArray.GetValue(0) instead. Or else, simply make that method return a string[] and you can use the [0] indexer.
public Array ParseThis(string sToParse)
{
return sToParse.Split(new char[] { '-' });
}
Corresponds to:
ctrlValue = sArray.GetValue(0);
And
public string[] ParseThis(string sToParse)
{
return sToParse.Split(new char[] { '-' });
}
Corresponds to:
ctrlValue = sArray[0];
But you could use the GetValue method as well in this case.
On another topic, you should check the returned object has at least one element before trying to access the first one.
You should avoid using the Array class directly in your code (unless you're calling its static methods). You should be returning the actual array type instead (string[] in your case)
From MSDN:
The Array class is the base class for language implementations that support arrays. However, only the system and compilers can derive explicitly from the Array class. Users should employ the array constructs provided by the language.
So a more appropriate declaration would be
public string[] ParseThis(string sToParse)
{
char cSplit = '-';
string[] sNew = sToParse.Split(new char[] { cSplit });
return sNew;
}
But you really don't need a function since you could just do
string[] parts = ctrlValue.Parse('-');
It's easy enough to write, of course, but in C# 2010, is there a built-in Join (or similar) method that will only add a separator if both the previous and next elements are non-null and non-empty?
In other words SmartJoin(", ","Hood","Robin") would produce "Hood, Robin" but SmartJoin(", ", "Robin Hood", string.Empty) would produce simply "Robin Hood".
How about this:
public void SmartJoin(string separator, params string[] Items)
{
String.Join(separator, Items.Where(x=>!String.IsNullOrEmpty(x)).ToArray());
}
There is no built-in join which you need.
Here's another way using "aggregate" method of linq
string result = new List<string>() { "Hood", "Robin" }.Aggregate(SmartJoin());
string result2 = new List<string>() { "Robin Hood", "" }.Aggregate(SmartJoin());
private static Func<string, string, string> SmartJoin()
{
return (x, y) => x + (string.IsNullOrEmpty(y) ? "" : ", " + y);
}
NotherDev was right, strictly speaking, there is no such method build in, but still #CodingGorila solution helped me, and should be added to the next .NET version by my account, though I did still turn it into a static function and have it return a string to make it work in my situation:
public static string SmartJoin(string separator, params string[] Items) {
return String.Join(separator, Items.Where(x=>!String.IsNullOrEmpty(x)).ToArray());
}
NotherDev was right, strictly speaking, there is no such method build in, but still #CodingGorila solution helped me, and should be added to the next .NET version by my account, though I did still turn it into a static function and have it return a string to make it work in my situation:
public static string SmartJoin(string separator, params string[] Items) {
return String.Join(separator, Items.Where(x=>!String.IsNullOrEmpty(x)));
}
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);