The following code throws an IndexOutOfRangeexception:
var builder = ImmutableArray.CreateBuilder<Color>(5);
builder[3] = Colors.Red;
I expected this would work, as the documentation says the following:
ImmutableArray<T>.CreateBuilder<T>(Int32) Creates a mutable array that can be converted to an ImmutableArray without allocating new memory; Int32 = The initial capacity of the builder. returns a Builder
Builder class: A writable array accessor that can be converted into an ImmutableArray instance without allocating extra memory.
Builder[int32] Gets or sets the item at the specified index.
Nothing in the docs says this would be an invalid expectation.
The same code for a basic array passes:
var colors = new Color[5];
colors[3] = Colors.Red;
I expected to get "a mutable array" by using a Builder but a regular mutable array behaves differently than the Builder.
For my app's purpose, indices are keys, and I need to be able to set the item at a given index just like a basic array.
Edit:
This works:
var arr = new Color[5];
arr[3] = Colors.Red;
var array = arr.ToImmutableArray();
This doesn't:
var builder = ImmutableArray.CreateBuilder<Color>(5);
builder[3] = Colors.Red;
var array = builder.ToImmutable();
For my question, I can accomplish it via the above but take the penalty of additional allocation.
ImmutableArray<T>.Builder has the same semantics as List<T>. Therefore, creating one with a count actually gives you one with a specified capacity and a count of 0. And just like with a list, accessing elements above the count is an error.
Instead, set Count directly to forcibly resize the array, filling it with default values:
var builder = ImmutableArray.CreateBuilder<Color>();
builder.Count = 5; // this will increase capacity if needed
builder[3] = Colors.Red; // no more errors!
You're trying to access a value that does not exist, (since you have not allocated any Color inside the array) giving you the
IndexOutOfRangeException
To fix this error, you can either create a new array like this:
var colors = new Color[]
{
Colors.Red,
Colors.Green,
Colors.Blue,
// Etc.
};
Or you can simply add the color you want.
colors.Add(Colors.Red);
Of course that this works with any other variable type, not only "Color"
The ImmutableArray.CreateBuilder method creates a builder that can be used to create an immutable array of the specified size. However, when you try to access an index of the builder using the square bracket notation, you are getting an "Index out of bounds" exception because the builder is empty and does not have any elements at that index yet.
you can use the builder.Insert() method to insert an element at a specific index, like this:
var builder = ImmutableArray.CreateBuilder<Color>(5);
builder.Insert(3,Colors.Red);
Alternatively, you can first add elements to the builder before accessing them. For example, you can do something like this
var builder = ImmutableArray.CreateBuilder<Color>(5);
for(int i=0;i<5;i++)
{
builder.Add(Colors.Black);
}
builder[3] = Colors.Red;
ImmutableArray.CreateBuilder creates the array, but doesn't set the size. Therefore, if you call Count on builder, you'll get 0.
You can add elements to the collection...
builder.Add(Colors.Red);
...which will increase the size, or (as Etienne de Martel pointed out in a comment), you can do...
builder.Count = 5;
...which will set the size, allowing you to set individual elements directly.
Related
I'm now doing a project about solving a Magic cube problem. I want to create an array to remember the steps like this:
char[] Steps = new char[200];
Each time I do the 'F','B','R','L','U','D' turn method, it will add a 'F','B','R','L','U','D' character in the array.
But when I want to get the length of the steps, it always shows 200.
for example:
char[] steps = new char[5];
and now I've already added 3 steps:
steps[] = {'f','b','f','',''};
How can I get the length '3'?
Or is there any alternative method I can use that I don't need to set the length at the beginning?
you can just use List<char> but if performance is really critical in your sceanario you can just initialize the initial capacity
something like the following
List<char> list = new List<char>(200);
list.Add('c');
list.Add('b');
here count will return just what you have really added
var c = list.Count;
note in list you can apply Linq Count() or just use the Count property which does not need to compute like Linq and return the result immediately
You will get compilation error on this line
steps[] = {'f','b','f','',''};
As you cannot use empty char and you need to write steps instead of steps[].
I will suggest you to use string array instead and using LINQ get count of not empty elements in this way:
string [] steps = {"f","b","f","",""};
Console.WriteLine(steps.Where(x=>!string.IsNullOrEmpty(x)).Count());
To count non-empty items using System.Linq:
steps.Count(x => x != '\0');
Your code doesn't compile since '' isn't allowed as a char, but I'm assuming that you mean empty elements in a char array which are actually represented by '\0' or the Unicode Null. So the above condition simply counts the non null items in your array.
you could use a list of character that would make things a lot simpler like this :
List<char> steps = new List<char>();
and just add a line to the list for each steps :
char move = 'F';
steps.add(move);
finally then you can count the number of move in the list easily
int numberofmove = steps.count();
Why does assigning values to a List have to be done with Add but to an array it can be done with the [] operator?
For example:
string[] y = new string[10];
y[0] = "asdf"; //fine
List<string> x = new List<string>(10);
x[0] = "asdf"; //ArgumentOutOfRangeException
Shouldn't both have the same behavior?
Taking a look at the source code for List(of T), your see that the indexed property getter/setters look like this:
// Sets or Gets the element at the given index.
//
public T this[int index] {
get {
// Fllowing trick can reduce the range check by one
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
return _items[index];
}
set {
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
_items[index] = value;
_version++;
}
}
Notice that, before setting the corresponding item in the List's internal array, it first checks the private _size variable to make sure it is in range. _size is not set to the size of the array, however. Size is incremented/decremented in the List's various Add/Remove methods, so even if you instantiate a list with an initial capacity of 10, that is the internal capacity of the List's array. Here is the constructor:
// Constructs a List with a given initial capacity. The list is
// initially empty, but will have room for the given number of elements
// before any reallocations are required.
//
public List(int capacity) {
if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
_items = new T[capacity];
}
The _size is not set (and therefore remains as its initialized value of 0) unless you either use Add/Remove/AddRange/etc. or use the constructor that accepts an IEnumerable (in which case the size because the number of items in the IEnumerable).
It makes sense if you think about it. The idea of a list is so that you DON'T have to worry about the complexity (and ugliness) of numeric indexes and resizing/copying arrays when the capacity needs to change. The size of the internal array, after the List is instantiated, should be of no concern to the developer. If you want to micromanage how the internal array is utilized, then you should either create your own implementation, or just use an array.
The way you implemented your array is right.
The size of an array needs to be declared when it is created. There is no way around that.
However, Lists' sizes are more flexible. You can add as many elements as you want without having to declare an initial size. After you've added elements however, you can access or edit them through their index number. Here's an example.
You are getting that exception because technically the list doesn't fill an index until you actually add a value to it. Let me know if that clears it up.
//You can add your elements when you instantiate it
List<string> names = new List<string>{"Alex", "Tommy", "Bob"};
//Or you can add them later
List<string> cities = new List<string>();
cities.Add("Denver");
cities.Add("New York");
//Now that they are created you can access or edit any of the elements within them.
names[2] = "Gerard";
cities[1] = "San Francisco";
The internal structure of a list is different of an array. While in a array you have a size of items defined on its definition, the amout of memory necessary to have these objects is realocate in memory by the CLR.
In a list<T> you can define the maximum of items in a list. That is (part of) the reason you have to call the Add method to add objects in a list<T>. You can define a initial Capacity for a list as you did on the constructor. If you need to add more than the capacity, the list will rearrange it for you. The framework manages for you how much items you have on the list.
Another important thing is that in both cases, you can access by index. For sample:
var obj = list[1];
var obj2 = array[1];
In a case that you do not have the 1 index on the list<T>/array, in an array, you get the default(T) (considering T as your type) and in a list you will get an Exception.
This constructor does not create any elements in list. It just reserves memory for items that could be added to this list.
You still have to insert items to the list manually before you can use then this way.
Upd:
This overload could help you when you dealing with large collections and you almost sure that you'll put about N items into your list. Thus you can reserve memory on creation and avoid memory allocation while you add items into this list (which could be slow sometimes).
I am trying to check if two arrays of equal size contain the same integers at the same indexes. If some element are not equal I want to return true, and otherwise return false.
public bool multipleSolutions(int[,] grid)
{
int[,] front = new int[9, 9];
front = grid;
int[,] back = new int[9, 9];
back = grid;
front = solve(front);
back = solveBackwards(back);
for (int r = 0; r < 9; r++)
{
for (int c = 0; c < 9; c++)
{
if (back[r, c] != front[r, c])
{
return true;
}
}
}
return false;
}
When tested separately, solve and solveBackwards give two different arrays, but when I try multipleSolutions it still gives me false (since they are two different arrays, I want it to return true).
Since the test logic is correct the most likely cause to this error is that the implementation of solve and solvebackwards changes the array passed in and returns the same array.
For both the call to solve and to solveBackwards the array identified by the parameter grid is passed in. So if solve changes the passed-in array then the input for solveBackwards has been changed accoring to the first run. Which might affect solveBackwards. The result wouldn't differ though because under th above assumption when solveBackwards is done. both front and back would then be the result of the solveBackwards
assumptions
solve and solveBackwards alters the array passed in
the return value of solve and solveBacrwards are the array passed in
EDIT
Seeing the the assumptions are correct you could insert this as the first line in both solve and solveBackwards
var temp = new int[9,9]
Array.Copy(grid, 0, temp, 0, grid.Length);
and then use temp through the implementation of solve and solvebackwards.
Alternatively you could do the same for front and back before passing them in as an argument
however you should then change the return type of the two methods. Specifying a return type is indicative of returning a different object and not mutating the argument. This is also why I'd prefer the first option (copying the array inside the method)
However even better in my opinion would be to iterate the input array and constructing an inemurable with the result
The problem is that you put the grid array in both the front and back variables. When you assing an array to an array variable, it doesn't copy the data from one array to another, it copies the reference to the array object. All your references will end up pointing to the same array object.
To copy the data from one array to another you can use the Copy method:
int[,] front = new int[9, 9];
Array.Copy(grid, front, grid.Length);
int[,] back = new int[9, 9];
Array.Copy(grid, back, grid.Length);
Now you have two new array objects that contain the data from the original grid.
So I have some code which stores some data in an array. When new data comes in it is put in a new array item (The totalnumber of array items) then the total number of array items is added too ready for the next bit of data. But when I try to add data into the array, be it array[0] or whatever it throws array index out of bounds?
Declaration:
string[] TabMessages = { };
int TotalTabs = 0;
Using it:
DevComponents.DotNetBar.TabItem Tab = TabStrip.CreateTab(TabName);
Tab.Tooltip = id + "|" + TabIndex;
TabMessages[TotalTabs] = "";//index out of bounds of array
TabStrip.SelectedTab = Tab;
TotalTabs++;
Any help, this is really annoying me because it's throwing the error about the index being out of bounds of the array when I'm trying to create a new entry to the array...
Arrays are a static length. You have defined an array of 0 length, then tried to access an element in the array that does not exist. Either you have to create a large enough array to hold all of the values you intend to use, or use a non-static collection like List<string> instead of a static-sized one like string[].
List<string> TabMessages = new List<string>();
TabMessages.Add("");
If you want something you can access by index, but don't want to supply all possible values, use a dictionary:
Dictionary<int, string> TabMessages = new Dictionary<int, string>();
TabMessages[TotalTabs] = "";
Arrays in C# are not dynamic - they are fixed size. Try using something list a List<string> and using the Add method to insert a new entry into it.
TabMessages is an array of 0 elements (that's how you declared it). As such, you won't be able to add (or set) any element on it - you'll get an index out of bounds exception every time.
This code:
string[] TabMessages = { };
is equivalent to:
string[] TabMessages = new string[0];
it means you created array which size 0. That is why you got this kind of exception. So you can use List<string> instead with dynamic size:
var TabMessages = new List<string>();
Then you can add the first item:
TabMessages.Add(string.Empty);
Or, create string array with fixed size depending on your business rule:
string[] TabMessages = new string[5]; // create string array with 5 elements
Array's are defined as having a fixed size. Declaring string[] TabMessages = {} is the same as string[0] Tabmessages;
You can resize an array (but I think it is a moderately expensive process) - see http://www.dotnetperls.com/array-resize
Alternatively (and preferably), try using some type of List construct
I want to define an array of strings but I don't know the number of strings I'll need to store in it. Can I define such an array, and how can I insert strings into it?
Better use List like this:
List<string> names = new List<string>();
names.Add(name); ///whatever string you want to insert
Later if you need array of names, call:
string[] arr = names.ToArray();
If you have to use an array of strings then you should know the size upfront. If you don't know the size, then you can initialize array of some default length (say 10).
The things that you have to do are:
Keep the count of strings already added in array
If it reaches the default length, you have re-initialize the array with a bigger length (say 15) and copy all existing strings to this new array.
You have to keep checks of the boundaries of this array, you don't want to read from indexes you haven't used yet (i.e. if the index is greater then count)
So its better to use list rather then doing all this stuff by yourself
You can use a List<string>, this will expand as you add items to it.
List<string> myList = new List<string>();
myList.Add("string1");
myList.Add("string2");
It can easily be converted to an array if needed:
string[] stringArray = myList.ToArray();
If you don't know the exact number of items you will need, an array may not be a good choice, as you will need to resize it (which is an expensive operation).
I would use the List class. You can add as much as you need without having to know how much you're going to put in there. If you do have some idea as to how much will be going in the list, you can use the capacity argument of List's constructor to prevent performance problems.
int capacity = 3;
var listOfNames = List<string>(/* optional */ capacity);
listOfNames.Add("My Name 1");
listOfNames.Add("My Name 2");
listOfNames.Add("My Name 3");
var namesArray = listOfNames.ToArray();
I added the namesArray line in there in case you really needed an array instead of a List for some reason.
See this page to see what all you can do with a List.
You can use the following, as Oded mentioned above (or below), it will auto expand when items are added to it.
List<String> l = new List<String>();
l.Add("your string here");
...And if you'd like to iterate, then:
foreach(string i in l)
{
// Do something with each item (i);
}
...And to have an Array:
String[] a =
l.ToArray();
Use List<T>. E.g.
var list = new List<string>();
list.Add("string1");
if you need the list to be an array, List<T> has a ToArray() method.
Internally List<T> stores the data as an array of strings. When more space is required, it will allocate a new array of double the size of the current and copy all the references to the new array. I.e. you don't have to do anything, but if the code is performance critical, you may want to supply a default capacity when creating the list.
ArrayList will do the trick too.
ArrayList alist = new ArrayList();
alist.Add(String1);
alist.Add(String2)