I'm trying to make some test data with which to test some functionality of my code. To this end, I need a double[][]. I am trying to do with a function that takes a double[][] as an input parameter and copying onto it a local variable containing the test data. However, I get an error that I don't quite understand (I'm sure it's a very basic error, which is why I'm unable to Google it), understanding/fixing which I'd appreciate any help.
private void makeData(double[][] patterns)
{
double[][] data = new double[2][];
// exists so that I can change `data` easily, without having to change the core functionality of copying it over to `patterns`
data[0] = {1.0,8.0}; // error!
// copy over everything from data into patterns
}
The line marked in the above code is giving me the error Only assignment, call, increment, decrement, and new objects can be used as a statement. To this, my reaction is "Isn't data[0] = {1.0,8.0}; an assignment?
I'm fairly confused, so I'd appreciate any help
You want to do
data[0] = new[] {1.0, 8.0};
The curly brace initializers are only valid if you're creating an object/array. They don't work by themselves.
You can specify the type specifically:
data[0] = new double[] {1.0, 8.0};
But you don't have to if the compiler can infer the right type (which, in your case, it can).
Just replace:
data[0] = {1.0,8.0};
by:
data[0] = new double[] { 1.0, 8.0 };
The compiler has to know explicitly what to assign to data[0]. It doesn't infer it from the type of data[0].
You should to initialize your subarray first.
double[][] data = new double[2][];
data[0] = new double[] {1.0f, 8.0f};
Related
Okay, I'll caveat this question with two things. One, I'm not as smart as you (I'm really not). Second, I may have found an answer to my own question, but want to verify.
I'm attempting to declare multiple arrays at the same time. It looks something like this. The first is just declaring a single array, while the second tries to declare both profit_Normal and profit_High in the same line:
double [] tradeType_Active = new double [15];
double [] profit_Normal, profit_High = new double [5];
Can I do this? I currently use this syntax for declaring non-array values with commas, like this:
double
BUpper,
BUpper_Prev,
BUpper_Prev2;
Please let me know when you have a moment.
Your line of code
double[] profit_Normal, profit_High = new double[5];
does declare multiple double[]. What it doesn't to is to initialize all of them. It initializes only the second one.
If you have the following line:
double[] a, b, c, d = new double[5];
what happens is that you are declaring 4 references of arrays of double. For each array you declare you must initialize it - which you are doing only for the last.
To initialize multiple arrays you need to actually initialize them:
double[] profit_Normal = new double[5], profit_High = new double[5];
The difference between the arrays case and this double BUpper, BUpper_Prev, BUpper_Prev2; is that arrays are reference types that their default value is null and must be initialized, whereas doulbe's default value is 0.
Yes, this is absolutely allowed, as long as you keep [] in the declaration to indicate that you are declaring an array:
double[] a = new double[4], b = new double[5];
The double[] part is the type of variables being declared. In your case, that's an array of double.
Note that the only difference between the above and your second declaration is that you did not initialize the profit_Normal variable.
You can use the same syntax you currently use, but in order to instantiate each one as well as declaring it, it would look like this, with = new double[5] after each one:
double[]
profit_Normal = new double[5],
profit_High = new double[5];
I have two sets of dictionaries that each contain the same keys and have initialized values.
Using unsafe code, I would like to swap their addresses:
Dictionary<string, List<object>> d1 = ...
Dictionary<string, List<object>> d2 = ...
unsafe void SwapEntries(string index)
{
int* tmp = &d1[index];
&d1[index] = &d2[index]
&d2[index] = tmp;
}
Assuming I've recalled my pointer arithmetic properly, the output I'm looking for would be this:
d1 = new Dictionary<string, List<int>>() { "a", { 1, 2, 3 } };
d2 = new Dictionary<string, List<int>>() { "a", { 4, 5, 6 } };
SwapEntries("a");
Console.WriteLine(d1["a"]); //4,5,6
Console.WriteLine(d2["a"]); //1,2,3
However, when I try to write this, I get the compile error "Cannot take the address of the given expression."
1) Is there a faster way of performing the address swap that I've missed? Performance is the only priority here.
2) Is my pointer arithmetic correct?
3) Do I need to move to a wrapper or a different data structure entirely in order to be able to perform the address swap as described?
I agree with Martin Ullrich's answer.
The expression d1[index] is not a variable. It is an invocation of the get accessor of the indexer defined by Dictionary<,>. You cannot take a pointer to that with the & operator.
Besides, in this case, the type of it is List<object>. You can only take pointers to value types, and List<> is a class type.
Even if you did have the true storage location, and it was of type object[], it would still be impossible since the element type of the array is object. So arr[0] (corresponding to d1[index][0]) would be a class type again, and you cannot take the address of that.
Scott Chamberlain's comment to your question gives an easy approach. Just use
void SwapEntries(string index)
{
var tmp = d1[index];
d1[index] = d2[index];
d2[index] = tmp;
}
This just involves passing around references to the two existing List<object> instances in question.
Automatic pointers to dictionary members aren't supported - they only work for Arrays or data types that use C# 7's "ref return" feature for indexers, properties or methods.
If you wanted to actually take the ref addresses of the two locations, there is now an option for it
CollectionsMarshal.GetValueRefOrNullRef(d1, "a")
So if you had a Swap function which accepted pointers:
void Swap<T>(ref T a, ref T b)
{
var tmp = a;
a = b;
b = tmp;
}
You could call it like this
Swap(ref CollectionsMarshal.GetValueRefOrNullRef(d1, "x"),
ref CollectionsMarshal.GetValueRefOrNullRef(d2, "x"));
shaplab
The benefit of this over just using normal dictionary indexers is that you only look up each location once, rather than once for get and once for set.
Consider this contrived, trivial example:
var foo = new byte[] {246, 127};
var bar = foo.Cast<sbyte>();
var baz = new List<sbyte>();
foreach (var sb in bar)
{
baz.Add(sb);
}
foreach (var sb in baz)
{
Console.WriteLine(sb);
}
With the magic of Two's Complement, -10 and 127 is printed to the console. So far so good. People with keen eyes will see that I am iterating over an enumerable and adding it to a list. That sounds like ToList:
var foo = new byte[] {246, 127};
var bar = foo.Cast<sbyte>();
var baz = bar.ToList();
//Nothing to see here
foreach (var sb in baz)
{
Console.WriteLine(sb);
}
Except that does not work. I get this exception:
Exception type: System.ArrayTypeMismatchException
Message: Source array type cannot be assigned to destination array type.
I find this exception very peculiar because
ArrayTypeMismatchException - I'm not doing anything with arrays, myself. This seems to be an internal exception.
The Cast<sbyte> works fine (as in the first example), it's when using ToArray or ToList the problem presents itself.
I'm targeting .NET v4 x86, but the same occurs in 3.5.
I don't need any advice on how to resolve the problem, I've already managed to do that. What I do want to know is why is this behavior occurring in the first place?
EDIT:
Even weirder, adding a meaningless select statement causes the ToList to work correctly:
var baz = bar.Select(x => x).ToList();
Okay, this really depends on a few oddities combined:
Even though in C# you can't cast a byte[] to an sbyte[] directly, the CLR allows it:
var foo = new byte[] {246, 127};
// This produces a warning at compile-time, and the C# compiler "optimizes"
// to the constant "false"
Console.WriteLine(foo is sbyte[]);
object x = foo;
// Using object fools the C# compiler into really consulting the CLR... which
// allows the conversion, so this prints True
Console.WriteLine(x is sbyte[]);
Cast<T>() optimizes such that if it thinks it doesn't need to do anything (via an is check like the above) it returns the original reference - so that's happening here.
ToList() delegates to the constructor of List<T> taking an IEnumerable<T>
That constructor is optimized for ICollection<T> to use CopyTo... and that's what's failing. Here's a version which has no method calls other than CopyTo:
object bytes = new byte[] { 246, 127 };
// This succeeds...
ICollection<sbyte> list = (ICollection<sbyte>) bytes;
sbyte[] array = new sbyte[2];
list.CopyTo(array, 0);
Now if you use a Select at any point, you don't end up with an ICollection<T>, so it goes through the legitimate (for the CLR) byte/sbyte conversion for each element, rather than trying to use the array implementation of CopyTo.
I'm trying to walk through a bunch of items, each item has an array of List<> objects that I want to convert to an array of arrays.. Here's the code to do that:
foreach (IngredientNode i in _snapshot._ingredientMap.Values)
{
for (int c = 0; c < NUM_TAGS; c++)
{
if (i.RecipesByTag[c] == null) continue;
i.RecipesByTag[c] = i.RecipesByTag[c].ToArray<RecipeNode>();
} <--- EXCEPTION
}
RecipesByTag has a static type of IEnumerable<RecipeNode>[]. However, its dynamic type is List<RecipeNode>[]. I want to go through each one of those and convert the dynamic type of RecopeNode[]. Under the debugger, this works and i.RecipesByTag gets converted. However, the last curly brace then throws the exception:
Attempted to access an element as a type incompatible with the array.
I have a feeling there's some sort of stack corruption going on. Can someone explain what's happening at a technical level here? Thanks!
Mike
You shouldn't have to specify the type argument for the ToArray method, it should be inferred from it's usage, if you are using strongly typed collections. This is a generic type casting problem. You are trying to put elements in an array of some incompatible type.
Your problem should boil to this (these arrays are covariant):
object[] obj = new string[1];
obj[0] = 5; // compiles fine, yields runtime error
Now, the same thing, with different types (these arrays are also covariant):
IEnumerable<int>[] x = new List<int>[1];
x[0] = new int[1]; // compiles fine, yields runtime error
It should be obvious why the type system doesn't like this. Basically, you look at it as if it was an array of IEnumerable<int> but it's actually an array of List<int>. You can not put an unrelated type array of int, into that array.
I believe Eric Lippert explains this very well on his blog.
Okay I think I figured out what's going on.. I have an array of Enumerables. At first, this was an array of pointers to list objects. I instead made this an array of other arrays, in other words I converted my array into a multidimentional array. Since a multidimentional array is consecutive in memory (as opposed to an array of pointers to other arrays), doing this completely corrupted the array in memory. At least that's my theory.
What I did is completely recreate i.RecipesByTag from scratch. Something like this:
List<RecipeNode[]> temp = new List<RecipeNode[]>();
for (int c = 0; c < NUM_TAGS; c++)
{
RecipeNode[] nodes = (i.RecipesByTag[c] == null) ? null : i.RecipesByTag[c].ToArray<RecipeNode>();
temp.Add(nodes);
}
i.RecipesByTag = temp.ToArray();
This works perfectly.
I've always wanted to be able to use the line below but the C# compiler won't let me. To me it seems obvious and unambiguos as to what I want.
myString.Trim({'[', ']'});
I can acheive my goal using:
myString.Trim(new char[]{'[', ']'});
So I don't die wondering is there any other way to do it that is closer to the first approach?
The string.Trim(...) method actually takes a params argument, so, why do you not just call:
myString.Trim('[', ']');
Others have concentrated on the specific example (and using the fact that it's a parameter array is the way to go), but you may be interested in C# 3's implicit typing. You could have written:
myString.Trim(new[] {'[', ']'});
Not quite as compact as you were after, as you still need to express the concept of "I want to create an array" unless you're writing a variable initializer, but the type of the array is inferred from the contents.
The big use case for this is anonymous types:
var skeets = new[] {
new { Name="Jon", Age=32 },
new { Name="Holly", Age=33 },
new { Name="Tom", Age=5 },
new { Name="Robin", Age=3 },
new { Name="William", Age=3 }
};
Here you couldn't write the name of the type, because it doesn't have a name (that's expressible in C#).
One other point to make about your specific example - if you're going to use this frequently (i.e. call the Trim method often) you may want to avoid creating a new array each time anyway:
private static readonly char[] SquareBrackets = {'[', ']'};
public void Whatever() {
...
foo = myString.Trim(SquareBrackets);
...
}
This will work too ...
myString.Trim( '[',']' );
Note the params declaration in the defition of Trim, it let's you pass as many arguments as you want and takes them as an array.
You could also try this:
myString.Trim("[]".ToCharArray());