Convert array element as concatenated string to double in C# - c#

I'm (very) new to C#; I'm sure the solution here is simple but I can't figure it out.
Suppose I have a simple array of temperatures for Friday. I receive an abbreviation for the day and an hour (integer) from somewhere and I want to use it to print an element from the array:
using System;
public class Program
{
public static void Main()
{
double[] Friday = {54.5, 61.0, 63.5, 58.0};
string Today = "Fri";
int Hour = 1;
double parsed = Convert.ToDouble(Today + "day[" + int + "]");
Console.WriteLine(parsed);
}
}
Given these conditions, how do I output 61.0? Then end result should be equivalent to Console.WriteLine(Friday[1]);

If I really wanted to achieve that I would use a dictionary:
Dictionary<string, double[]> dayToValues =
new Dictionary<string, double[]>
{
{"Monday", new double[] {1.0, 2.0, 3.0} },
{"Friday", new double[] {4.0, 5.0, 6.0} }
};
string today = "Fri";
int hour = 0;
double firstHourValue = dayToValues[today + "day"][hour];
Console.WriteLine(firstHourValue); // prints "4"
If you really need to dynamically build the name of a variable and access it, you have to use reflection. Something like:
string fieldName = today.ToLower() + "day";
double[] todays = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as double[];
Console.WriteLine(todays[1]); // prints "8"
This assumes that your have a private field in the current class:
double[] friday = { 7.0, 8.0, 9.0 };
Of course the reflection code depends on the exact location and scope of the variables. And obvioulsy you would need some null reference checks to use it in the real world. Anyway, using reflection looks quite irrelevant for what seem to be your needs. Use it only if you really have to.

c# uses zero-relative indexing. This means that the 1st element in the array has an index of zero. So you most likely mean Friday[0].
c# also has the ToString method on all objects. This returns a "human readable" representation of the object. So you can do
Console.WriteLine(Friday[0].ToString());
Also, WriteLine will auto-magically convert any object passed to it into its string repsentation. So this will also work
Console.WriteLine(Friday[0]);
If you want text and a value, then use a Format string, as in
Console.WriteLine("Friday {0}", Friday[0]);
See https://msdn.microsoft.com/en-us/library/system.string.format%28v=vs.110%29.aspx for more details on format strings.

Related

add duck-typed struct to dictionary c#

I want to add a duck-typed struct to an dictionary but i get the following error:
Argument 2: cannot convert from '[] options>' to 'UnityEngine.Object'
This is the code i have:
public class Dynamic_Interface
{
private static Dictionary<int, Object> Interface_steps = new Dictionary<int, Object>();
Dynamic_Interface()
{
var sentences = new[]
{
new
{
identifier = 1,
text = "string explain",
options = new[]
{
new
{
next = 2,
value = "this is the first option"
},
new
{
next = 2,
value = "this is the second option"
},
new
{
next = 2,
value = "this is the third option"
},
new
{
next = 2,
value = "this is the fourth option"
},
}
},
new
{
identifier = 2,
text = "string explain second var",
options = new[]
{
new
{
next = 3,
value = "this is the second first option"
},
new
{
next = 3,
value = "this is the second second option"
},
new
{
next = 3,
value = "this is the second third option"
},
new
{
next = 3,
value = "this is the second fourth option"
}
}
},
};
foreach (var sentence_obj in sentences)
{
Interface_steps.Add(sentence_obj.identifier, sentence_obj);
}
}
}
So in the end i want a dictionary containing each object in the sentences[] that has the the identifier key as name in the dictionary.
I am used to to javascript and this is really my first time doing c# so sorry for the beginner mistake. But i really cant seem to find how to get this to work.
If something is unclear let me know so i can clarify..
So, what is happening here?
When we take a closer look at the error message
Argument 2: cannot convert from '[] options>' to 'UnityEngine.Object'
it tells us that we are trying to convert the options array to the type UnityEngine.Object. Hmmm. this is weird we didn't define our Dictionary with this Unity nonsense, so why is it using that instead of C#'s Object class?!
Well you are propably using other Unity classes an probably have something like
using UnityEngine;
in your namespace. The problem with C# is that it's Object class also resides in a namespace which is called System, making it only fully identifieable by using System.Object. So if you don't have
using System;
it will happily try to use UnityEngine.Object instead of System.Object when you type Object. Thus this weird compiler error will occur.
So just use System.Object and everything is fine right?
Well Yes. But there is more to the Story!
C# also has defined aliases for it's most common types - the so called built-in types:
bool System.Boolean
byte System.Byte
sbyte System.SByte
char System.Char
decimal System.Decimal
double System.Double
float System.Single
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
object System.Object
short System.Int16
ushort System.UInt16
string System.String
You will find that lowercase object is just an alias to System.Object. But wait! Doesn't that make object always use System.Object regardless of our using statements? The answer is yes, yes it does...
Let me illustrate by following example how tricky namespacing in C# can actually be:
public class Object
{
public string Name { get; set; }
}
public class TestConsole
{
public static void Main(string[] args)
{
Object fakeObject = new Object(); // -> Custom Object class
object realDeal = new object(); // -> System.Object
string name = fakeObject.Name // OK
name = realDeal.Name // NOT OK
}
}
So does that mean that we should always use the built-in alias when using System classes? Not really but we should rather use the naming convention that is used by Microsoft. That means whenever you use the class like a datatype you should use the built-in and whenever you use static members of the class you should use it's full name. For example:
object humberto = "humberto";
string rudolf = "rudolf";
Object.Equals(humberto, rudolf);
Strong typing is one of advantages of C#, its a bit more verbose than ducktyping but saves you a lot of headache, if possible try to restrain from var, its a few characters shorter but if you use strong types its much harder to accidentally ask the compiler to do something different than what you actually want:
Two options for alternative approaches that seem to immediately stand out are
class myClass { int next; string value; };
Dictionary <int, myClass> dict;
or, possibly, although I think this is not quite what you are trying to do
Dictionary<int, Dictionary<int,string>> dict;
Second option doesn't require you to declare a class type, but remember that dictionaries require unique keys. It kind of reads that you want to use array index as a key, but then you still use a dictionary, is there a reason for that? My solutions might be a bit off, but I'd be happy to suggest more if you could explain what kind of lookup you want to make.
Maybe you want to combine the above into
Dictionary<int, Dictionary<int,myClass>> dict;

How to map variable names to array indices

Say I have an array of fixed size N, is there a way to map the elements to a list of N variable names?
I was thinking of something like:
variable1, variable2, variable3 = arrayOfSize3;
EDIT:
A few people have remarked that this would be useless and suggested that I am doing something wrong. Maybe I am, but this is a pretty common feature in dynamic languages so I was hoping C# had something elegant as an alternative.
If it helps, I can write what I need it for. I have parsed an HTML table and have an array of strings representing a row of the table. I made a class to represent the row with variables representing the data, but to store the data I have to manually set the names to each of the array elements. I know there are other ways to do this, but I was wondering more out of curiosity than anything else, what is the right way to map variables like this?
Their is no such assignment, but you can do like this:
var variable1 = arrayOfSize3[0];
var variable2 = arrayOfSize3[1];
var variable3 = arrayOfSize3[2];
Not production ready yet, but you can do this in C# 7 preview which comes with Visual Studio 15 preview. Using deconstruction matching, the following code works with Tuple
var (variable1, variable2, variable3) = tupleOfSize3;
This feature actually works with anything with a deconstructor method like this
public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }
Maybe array will have this extension. Please see What's new in C# 7.0
Tuples are a set of a fixed number values, each with its own name and type. Arrays, on the other hand, are a set of a variable number of anonymous values, all of the same type. These are two very distinct forms of aggregate types, and they really serve mostly disjoint use cases.
Having said that, it is possible to deconstruct an array (in C# 7 preview which comes with Visual Studio 15 preview)! You can do it by adding your own Deconstruct method as an extension method:
class C
{
public static void Main()
{
int[] x = new int[2];
var (a, b) = x;
}
}
static class ArrayUtilities
{
public static void Deconstruct(this int[] data, out int a, out int b)
{
a = data[0];
b = data[1];
}
}

Catching value of the concatenated variable

My environment is: W7 Ultimate 64 bits, VS2010 Ultimate, C#, WinForm, target XP and W7.
With the help of #dasblinkenlight, the concatenation on the for loop was very good.
I feel we are making great progress.
As you ca see, we are putting into the array sMntHour[d,h] the string "csv_001_01" if d=1 and h=1 and so on.
This csv_001_01, csv_001_02,.. ; are variables that contains an integer value.
csv_001_01=5111;
csv_001_02=236; // This is a sample, because has 365 days in normal year
// and 366 days in leaf year. "csv_day_hour"
Directly we could do this:
sMntHour[d,h] = csv_001_01.ToString(); // d is day and h is hour
sMntHour[d,h] = csv_001_02.ToString();
As we put the value of this concatenated variable in the array and not the name of the variables?
for(int d=1;d<=365;d++) //I'll put the code to not leap years.
{
for(int h=1; h<=24; h++)
{
sMntHour[d,h] = string.Format("csv_{0:000}_{1:00}", d, h)
}
}
If I understand what you mean, you have all the variable names and now you want to get their values.
You could do this using Reflection and you can create a dictionary where keys are the variable names and the values are the actual values. It is really hard to help without seeing how these variables are declared, are they fields / properties ? are the private, static ? etc... But something like this should work, in theory:
var type = this.GetType();
var values = sMntHour.OfType<string>()
.ToDictionary(
x => x,
x => (int)type.GetField(x).GetValue(this));
Then you can access the values using values["variable_name"]
Or if you don't want this, instead if you want to access them using index like [d,h] as mentioned in comments, do not store the variable names in the first place instead store the values in your array:
var type = this.GetType();
for(int d=1;d<=365;d++)
{
for(int h=1; h<=24; h++)
{
var name = string.Format("csv_{0:000}_{1:00}", d, h);
sMntHour[d,h] = (int)type.GetField(name).GetValue(this);
}
}
Ofcourse you need to change the type of sMntHour, in order to make it work.

Get a string to reference another in C#

I'm coming from a C++ background. This question has been asked before, but try as I might I cannot find the answer. Let's say I have:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
Can I create a string that references the above (neither of these will compile):
string a = ref ArrayOfReallyVeryLongStringNames[439]; // no compile
string a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
I do understand that strings are immutable in C#. I also understand that you cannot get the address of a managed object.
I'd like to do this:
a = "Donkey Kong"; // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong";
I have read the Stack Overflow question Make a reference to another string in C#
which has an excellent answer, but to a slightly different question. I do NOT want to pass this parameter to a function by reference. I know how to use the "ref" keyword for passing a parameter by reference.
If the answer is "You cannot do this in C#", is there a convenient workaround?
EDIT:
Some of the answers indicate the question was unclear. Lets ask it in a different way. Say I needed to manipulate all items in the original long-named array that have prime indices. I'd like to add aliases to Array...[2], Array...[3], Array...[5], etc to a list. Then, modify the items in the list using a "for" loop (perhaps by passing the list just created to a function).
In C# the "using" keyword creates an alias to a class or namespace. It seems from the answers, that it is not possible to create an alias to a variable, however.
You could create a wrapper that keeps a reference to the underlying array AND the index of the string:
public sealed class ArrayStringReference
{
private readonly string[] _array;
private readonly int _index;
public ArrayStringReference(string[] array, int index)
{
_array = array;
_index = index;
}
public string Value
{
get
{
return _array[_index];
}
set
{
_array[_index] = value;
}
}
public override string ToString()
{
return Value;
}
}
Then this will work:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439);
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!"
strRef.Value = "Donkey Kong";
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong"
You could make this more convenient to use by providing an implicit string operator so you don't have to use .Value to access the underlying string:
// Add this to class ArrayStringReference implementation
public static implicit operator string(ArrayStringReference strRef)
{
return strRef.Value;
}
Then instead of having to access the underlying string like this:
strRef.Value = "Donkey Kong";
...
string someString = strRef.Value;
You can do this:
strRef.Value = "Donkey Kong";
...
string someString = strRef; // Don't need .Value
This is just syntactic sugar, but it might make it easier to start using an ArrayStringReference in existing code. (Note that you will still need to use .Value to set the underlying string.)
The closest you can get is this:
unsafe
{
string* a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
}
Which gives an exception:
Cannot take the address of, get the size of, or declare a pointer to a managed type ('string')
So no, not possible...
Also read this MSDN article which explains what types can be used (blittable types).
When I do something like this in C#:
string a = "String 1";
string b = a;
a = "String 2";
Console.WriteLine(a); // String 2
Console.WriteLine(b); // String 1
The thing is, both "String 1" and "String 2" literals are created at the start of the program, and strings are always pointers: at first a references "String 1" literal and afterwards it references "String 2". If you want them to always reference the same thing, in C# you just use the same variable.
The string objects themselves are immutable in C#:
Because a string "modification" is actually a new string creation, you must use caution when you create references to strings. If you create a reference to a string, and then "modify" the original string, the reference will continue to point to the original object instead of the new object that was created when the string was modified.
When the string mutability is needed, for example, to concatenate a lot of strings faster, other classes are used, like StringBuilder.
To sum it up, what you're trying to do is impossible.
In C#, a String is an Object. Therefore String a = "Donkey Kong" says that a now have a reference to this string that is being allocated over the memory. Then all you need to do is:
ArrayOfReallyVeryLongStringNames[439] = a;
And that will copy the refrence (which you should be thinking of in C#!!!) to the location in the string.
BUT!! When you do a="new string";, a will get a new reference. See the example I made:
http://prntscr.com/3kw18v
You can only do this with unsafe mode.
You could create a wrapper
public class StringWrapper
{
public string Value {get;set;}
}
StringWrapper[] arrayOfWrappers = new StringWrapper[500];
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" };
StringWrapper a = arrayOfWrappers[439];
a.Value = "New Value";
What you are trying to do is universally discouraged, and actively prevented, in C#, where the logic should be independent of the memory model, however, refer to related SO question C# memory address and variable for some info.
EDIT 1
A more canonical approach to your actual problem in C# would be:
// using System.Linq;
string[] raw = new string[] { "alpha", "beta", "gamma", "delta" };
List<int> evenIndices = Enumerable.Range(0, raw.Length)
.Where(x => x % 2 == 0)
.ToList();
foreach (int x in evenIndices)
raw[x] = raw[x] + " (even)";
foreach (string x in raw)
Console.WriteLine(x);
/*
OUTPUT:
alpha (even)
beta
gamma (even)
delta
*/
If you really want to modify the original memory structure itself, then perhaps C++ is a more appropriate language choice for the solution.
EDIT 2
Looking around on SO, you may want to look at this answer Hidden Features of C#? to an unrelated question.
[TestMethod]
public void TestMethod1()
{
string[] arrayOfString = new string[500];
arrayOfString[499] = "Four Ninty Nine";
Console.WriteLine("Before Modification : {0} " , arrayOfString[499]);
string a = arrayOfString[499];
ModifyString(out arrayOfString[499]);
Console.WriteLine("after a : {0}", a);
Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]);
}
private void ModifyString(out string arrayItem)
{
arrayItem = "Five Hundred less one";
}
Of course you can, hehe:
var a = __makeref(array[666]);
__refvalue(a, string) = "hello";
But you would have to have a very good reason to do it this way.

string.Format fails at runtime with array of integers

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.

Categories