I have a Writline C# code. However each query will bring back a diffrent length (to be populated in a excel database). I can get the length, but I am unsure how to define the n value in the Writline query below (where n will be diffrent each time, I can get the length, but how to define the writeline). Many thanks.
sw.WriteLine(string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\......n)
I can get the length
Then you can make a format string:
var fmt = string.Concat(Enumerable.Range(0, theLength).Select(i => "{" + i + "}"));
If theLength is 3, your fmt string ends up as "{0}{1}{2}"
Other helpful factoid. The compiler takes this:
string.Format("....", a, b, c, ...);
And turns it into something like this:
var an_array = new object[]{ a, b, c, ... };
string.Format("...", an_array);
So if you already have an array there's nothing stopping you supplying it:
string.Format(fmt, your_array);
Methods that take a params arg are internally rewritten to take the N number of params as an array; you're always allowed to shortcut that and provide the array
Related
I have an array :
string[] arr = new string[2]
arr[0] = "a=01"
arr[1] = "b=02"
How can I take those number out and make a new array to store them? What I am expecting is :
int [] newArr = new int[2]
Inside newArr, there are 2 elements, one is '01' and the other one is '02' which both from arr.
Another way besides Substring to get the desired result is to use String.Split on the = character. This is assuming the string will always have the format of letters and numbers, separated by a =, with no other = characters in the input string.
for (var i = 0; i < arr.Length; i++)
{
// Split the array item on the `=` character.
// This results in an array of two items ("a" and "01" for the first item)
var tmp = arr[i].Split('=');
// If there are fewer than 2 items in the array, there was not a =
// character to split on, so continue to the next item.
if (tmp.Length < 2)
{
continue;
}
// Try to parse the second item in the tmp array (which is the number
// in the provided example input) as an Int32.
int num;
if (Int32.TryParse(tmp[1], out num))
{
// If the parse is succesful, assign the int to the corresponding
// index of the new array.
newArr[i] = num;
}
}
This can be shortened in a lambda expression like the other answer like so:
var newArr = arr.Select(x => Int32.Parse(x.Split('=')[1])).ToArray();
Though doing it with Int32.Parse can result in an exception if the provided string is not an integer. This also assumes that there is a = character, with only numbers to the right of it.
Take a substring and then parse as int.
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
As other answers have noted, it's quite compact to use linq. PM100 wrote:
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
You asked what x was.. that linq statement there is conceptually the equivalent of something like:
List<int> nums = new List<int>();
foreach(string x in arr)
nums.Add(Int32.Parse(x.Substring(2);
var newArr = nums.ToArray();
It's not exactly the same, internally linq probably doesn't use a List, but it embodies the same concept - for each element (called x) in the string array, cut the start off it, parse the result as an int, add it to a collection, convert the collection to an array
Sometimes I think linq is overused; here probably efficiencies could be gained by directly declaring an int array the size of the string one and filling it directly, rather than adding to a List or other collection, that is later turned into an int array. Proponents of either style could easily be found; linq is compact and makes relatively trivial work of more long hand constructs such as loops within loops within loops. Though not necessarily easy to work out for those unfamiliar with how to read it it does bring a certain self documenting aspect to code because it uses English words like Any, Where, Distinct and these more quickly convey a concept than does looking at a loop code that exits early when a test returns true (Any) or builds a dictionary/hashset from all elements and returns it (Distinct)
Again, I am a discrete mathematician, not a coder, but an trying to use C# for a paper I am working on and need some help.
I have a code to generate a set of random integers, based on user input, and printed them as a string separated by commas, but need to convert them into a vector (or an int array?). I am not exactly sure which is appropriate, but I cannot find much online about how to use either in C#. I need to be able to apply vector functions to them, so each entry still needs to be identifiable and an integer, but the vector needs to be able to vary in size depending on the user input.
If you already have a comma-delimited string, you can use the String.Split() method to split it based on the commas into an array and then you can convert each of these values into it's appropriate integer using the Int32.Parse() or Convert.ToInt32() methods respectively :
// The Split() method will yield an array, then the Select() statement
// will map each string value to it's appropriate integer and finally
// the last ToArray() call will make this into an actual array of integers
var output = input.Split(',').Select(n => Int32.Parse(n)).ToArray();
You can see an example of this in action here. If you needed to explicitly ignore possible empty entries and whitespace, you could use the following adjusted example :
var output = input.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries)
.Select(s => Int32.Parse(s.Trim()))
.ToArray();
An even safer approach still would be to only use values that could be properly parsed as integers via the Int32.TryParse() method as seen below :
// Split your string, removing any empty entries
var output = strings.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries)
.Select(n => {
// A variable to store your value
int v;
// Attempt to parse it, store an indicator if the parse was
// successful (and store the value in your v parameter)
var success = Int32.TryParse(n, out v);
// Return an object containing your value and if it was successful
return new { Number = v, Successful = success };
})
// Now only select those that were successful
.Where(attempt => attempt.Successful)
// Grab only the numbers for the successful attempts
.Select(attempt => attempt.Number)
// Place this into an array
.ToArray();
I want to know whether we can give the index of the string as Long data type.
var i=long.Parse(Console.ReadLine());
var result = testString[i-1];
the second line giving me the error by saying that "The best overloaded method match for 'string.this[int]' has some invalid arguments."
No you can't use long for most collection types (you haven't specified what testString is).
One way to get around this would be to segregate the string into a multi-part / multi-dimension array then use a multiplier to get which part of the array to check.
For example:
Your index is 100,000 and you have an array of shorts (32,767 length)...
string[,] testString = new string[100, 32766]; //Replace this with your Initialisation / existing string
var arrayRank = (int)Math.Round((double) 100000 / 32767, 0);
var arrayIndex = (int)Math.Round((double)100000 % 32767, 0);
//Test this works.
//testString[arrayRank, arrayIndex] = "test"; - Test to see that the array range is assignable.
var result = testString[arrayRank, arrayIndex]; //Test value is what we expect
This may not be the most efficient way to go about things, but it is a workaround.
No, it cannot accept a long. The only overload accepts an int indexer. You would need to change your code to int.Parse() instead of long.Parse()
There is no way to pass long as an index of array, compiler doesn't allow that.
Workaround can be converting the long to int, this is called narrow conversion.
var result= testString[(int)i)];
I created 3 strings:
string a = "abcdgfg";
string b = "agbfcd";
string c = "axcvn";
I want to create the following check but i can't find out how:
Need to check if in string a and string b there are the same latters (never mind the order or if a latter shown more than once, just need to check if the same latter appears on both strings).
Then i need to do the same check for string a and string c.
as you can see: string a and string b have the same latters, stringa a and string c don't.
after i do the checking i simply print a massage if the strings have the same latter or not
Can anyone show me how to do the cheking?
Edit:
after check "a" and "c", it o should print the first latter that came up and not match between "a" and "c"
Thanks
I would suggest to use a HashSet<T> and it's SetEquals:
var aSet = new HashSet<char>(a);
var bSet = new HashSet<char>(b);
bool abSame = aSet.SetEquals(b);
Edit
after check "a" and "c", it o should print the first latter that came
up and not match between "a" and "c"
Then you can use HashSet.SymmetricExceptWith:
if (!abSame)
{
aSet.SymmetricExceptWith(bSet);
Console.WriteLine("First letter that is either in a and not in b or in b and not in a: " + aSet.First());
}
By the way, this can also replace the SetEquals check:
aSet.SymmetricExceptWith(bSet); // removes all characters which are in both
if (aSet.Any()) // missing charaters in one of both strings
{
Console.WriteLine("First letter that is either in a and not in b or in b and not in a: " + aSet.First());
}
The original answer using Except + Any had a subtle bug. Checking the length is not sufficient if there are duplicates. So you need to check from both directions or use Distinct first. Both approaches are inefficient compared to the HashSet.SetEquals-method which is a O(n) operation.
bool abSame = !a.Except(b).Any() && !b.Except(a).Any();
private bool HaveSameLetters(string a, string b)
{
return a.All(x => b.Contains(x)) && b.All(x => a.Contains(x));
}
Need to check if in string a and string b there are the same latters (never mind the order or if a latter shown more than once, just need to check if the same latter appears on both strings).
You can do it like this:
bool same = a.Distinct().OrderBy(c => c)
.SequenceEqual(b.Distinct().OrderBy(c => c));
This simply sorts the characters of two strings and checks if the two ordered sequence are equal. You can use the same method for a and c.
Consider string.Format() whose parameters are a string and, among others in the overload list, an object[] or many objects.
This statement succeeds:
string foo = string.Format("{0} {1}", 5, 6);
as does this:
object[] myObjs = new object[] {8,9};
string baz = string.Format("{0} and {1}", myObjs;
as does an array of strings:
string[] myStrings = new string[] {"abc", "xyz"};
string baz = string.Format("{0} {1}", myStrings);
It seems that the integers, when specified individually, can be boxed or coerced to type object, which in turn is coerced to a string.
This statement fails at runtime.
int[] myInts = new int[] {8,9};
string bar = string.Format("{0} and {1}", myInts);
Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
Why doesn't or can't the int array be coerced or boxed to an object[] or string[]?
Out of a small bit of curiosity, why doesn't the compiler catch this?
The call fails with the same reason the following will also fail:
string foo = string.Format("{0} {1}", 5);
You are specifying two arguments in the format but only specifying one object.
The compiler does not catch it because int[] is passed as an object which is a perfectly valid argument for the function.
Also note that array covariance does not work with value types so you cannot do:
object[] myInts = new int[] {8,9};
However you can get away with:
object[] myInts = new string[] { "8", "9" };
string bar = string.Format("{0} {1}", myInts);
which would work because you would be using the String.Format overload that accepts an object[].
Your call gets translated into this:
string foo = string.Format("{0} {1}", myInts.ToString());
which results in this string:
string foo = "System.Int32[] {1}";
So as the {1} doesn't have a parameter, it throws an exception
I think the concept you are having an issue with is why int[] isn't cast to object[]. Here's an example that shows why that would be bad
int[] myInts = new int[]{8,9};
object[] myObjs = (object[])myInts;
myObjs[0] = new object();
The problem is that we just added an object into a int array.
So what happens in your code is that myInts is cast to object and you don't have a second argument to fill in the {1}
Short way to make it work (not the most optimal though):
int[] myInts = new int[] { 8, 9 };
string[] myStrings = Array.ConvertAll(myInts, x => x.ToString());
// or using LINQ
// string[] myStrings = myInts.Select(x => x.ToString()).ToArray();
bar = string.Format("{0} and {1}", myStrings);
This is quite an old question, but I recently got the same issue. And I haven't seen an answer that works for me, so I'll share the solution I found.
Why doesn't or can't the int array be coerced or boxed to an object[] or string[]? Why it isn't boxed, I don't know. But it can be boxed explicitly, see solution below.
Why doesn't the compiler catch this? Because the compiler misinterprets the situation: The type isn't exactly an object array, so it doesn't know what to do with it and decides to perform a .ToString() on the int array, which returns one single parameter containing the type name rather than the parameter list itself. It doesn't do that with a string array, because the target type is already a string - but with any other kind of array the same issue happens (for example bool[]). Consider var arr1 = new int[]{1,2}; with string.Format("{0}", arr1): As long as you have only {0} in the format string, you get only the type name "System.Int32[]" back (and no exception occurs). If you have more placeholders, e.g. string.Format("{0}{1}", arr1), then the exception occurs - because arr1 is misinterpreted as one parameter - and for the compiler, a 2nd one is missing. But what I think is a conceptional bug is that you can't convert arr1, i.e. if you try to do (object[])arr1- you're getting:
CS0030 Cannot convert type 'int[]' to 'object[]'
Solution:
Filling in each element of the int array is not a solution that works for me, because in my project I am creating a format template string dynamically during runtime containing the {0}...{n} - hence I need to pass an array to String.Format.
So I found the following workaround. I created a generic helper function (which of course could be an extension method too if you prefer):
// converts any array to object[] and avoids FormatException
object[] Convert<T>(T[] arr)
{
var obj = new List<object>();
foreach (var item in arr)
{
obj.Add((object)item);
}
return obj.ToArray();
}
Now if you try that in the example below which is showing up the FormatException:
// FormatException: Index (zero based) must be greater than or equal to zero
// and less than the size of the argument list
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", arr1).Dump();
Fix: Use Convert(arr1) as 2nd parameter for string.Format(...) as shown below:
// Workaround: This shows 1212, as expected
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", Convert(arr1)).Dump();
Try example as DotNetFiddle
Conclusion:
As it seems, the .NET runtime really misinterprets the parameter by applying a .ToString() to it, if it is not already of type object[]. The Convert method gives the runtime no other choice than to do it the right way, because it returns the expected type. I found that an explicit type conversion did not work, hence the helper function was needed.
Note: If you invoke the method many times in a loop and you're concerned about speed, you could also convert everything to a string array which is probably most efficient:
// converts any array to string[] and avoids FormatException
string[] ConvertStr<T>(T[] arr)
{
var strArr = new string[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
strArr[i]=arr[i].ToString();
}
return strArr;
}
This is working as well. To convert from a different datatype, such as a dictionary, you can simply use
string[] Convert<K,V>(Dictionary<K,V> coll)
{
return ConvertStr<V>(coll.Values.ToArray());
}
Update: With string interpolation, another short way to solve it is:
var baz = string.Format("{0} and {1}", myInts.Select(s => $"{s}").ToArray());
Your string.Format is expecting 2 arguments ({0} and {1}). You are only supplying 1 argument (the int[]). You need something more like this:
string bar = string.Format("{0} and {1}", myInts[0], myInts[1]);
The compiler does not notice the problem because the format string is evaluated at runtime. IE The compiler doesn't know that {0} and {1} mean there should be 2 arguments.
This works:
string bar = string.Format("{0} and {1}", myInts[0], myInts[1]);
The compiler doesn't catch it because it doesn't evaluate your format string.
The example you gave up top doesn't match what you're trying to do down below... you provided two {} and two arguments, but in the bottom one you only provided one argument.