.Net List<T> insert - c#

I am trying to do
var test = new List< int>(10);
test.Insert(1, 0);
or
test[1] =0;
I am getting exception at this.
How can I insert to list?
Thanks
space is there to get this editor show things properly.

var test = new List<int>(10);
test.Add(1);
or
var test = new List<int>(10);
test.Insert(0, 1) // inserts the value in the first position
UPDATE
I missed your original intent. To do what you want, you just have to initialize each position in the list with an initial value. The not so suggested way would be something like:
//var test = new List<int>(10){0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
var test = new List<int>(10);
test.AddRange(Enumerable.Repeat(0, 10)); // Thanks to Ahmad
test[3] = 10; // works now

You're allocating an empty list with the capacity to hold 10 items before re-allocating. Then you're inserting into the middle of it. This is why it's failing.
edit
You seem to think that it's like an array, where it actually allocated ten slots to start with. It's not. If you want ten slots, you need to add them yourself. Once you do, it's possible to reference positions in the middle.

Assuming you want to create a list of 10 ints and set the value of 1. You could
var test = Enumerable.Repeat<int>(0, 10).ToList();
test[1] = 0;
Which would create a List of 10 ints (all equal to 0) and then set the value of index 1 to 0. Obviously as the list is initialised with values of 0, the second line is unnecessary.

Thanks for all the answers.
My list is
var x = new List<ISomeInterface>(10);
I cannot do repeat on interface and I don't know what object it is. Since it's pretty generic.
The solution I used:
var x = new ISomeInterface[10];
x.ToList();

The integer parameter of the list constructor defines the capacity of the list, which means how many elements the list can hold maximally. After you have instanciated the list, it is empty and is capable of holding 10 values (although I'm not sure if 10 isn't just the initial capacity, which will grow on demand). Anyway, when you are trying to insert at position 1 (the second element), you get an exception because the list does not contain any elements.
I think what you like to use is an array:
int[] integers = new int[10]; // Creates an array which holds 10 values,
// initially all values are zero.
integers[1] = 123; // Modifiy the value at index 1.
Best Regards
Oliver Hanappi

You cannot insert into a position until after you've added enough elements to make the list at least that large. This is clearly documented in the List's Insert documentation:
ArgumentOutOfRangeException can be thrown when:
index is less than 0, or
index is greater than Count.
If you're just trying to set specific elements, you can add in all 10 elements, then use the indexer:
test[1] = 0;
Otherwise, you can add an element, then insert:
test.Add(0); // Now the list has an element
test.Insert(1,0); // Insert into element 1...

Related

How to remove an element of List<int[]> in C#

I'm trying to program a Sudoku solver in C# in which I'm using a List of an integer array with all the positions of empty fields, because I need them in my algorithm.
In the progress of solving the Sudoku I need to remove those positions which got filled with a number. But somehow my list with empty positions does not get smaller, when I use the Remove-method.
I will explain my problem with a simplified example:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
test1.Remove(new int[] { 1, 7 });
The first line generates the list with my one dimensional integer array (which always consists of two values - one for the column and one for the row-number). The empty positions get added in a method, but in this example I just added them in these two lines.
Later on in my algorithm, I want to remove elements by using the Remove-function similarly to the Add-function. It throws no errors, even while compiling. However, it's not removing anything.
I tried using the RemoveAll-method, although I don't really understand, how it works and therefore didn't find a correct solution for my problem.
By trying out a List of integers (not an integer array) the Remove-method works perfectly, but in the case of an array it doesn't seem to work this way.
Even creating a seperat variable rem
int[] rem = new int[] { 1, 7 };
test1.Remove(rem);
does not work.
I'm a beginner so I don't really know if a List of arrays is the best solution in my case.
bool IntArrayPredicate(int[] element)
{
return element.SequenceEqual(new int[] { 2, 3 });
}
List<int[]> listOfIntArray = new List<int[]>();
listOfIntArray.Add(new int[] { 0, 0 });
listOfIntArray.Add(new int[] { 1, 7 });
listOfIntArray.Add(new int[] { 2, 3 });
listOfIntArray.RemoveAll(element => element.SequenceEqual(new int[] { 1, 7 })); //It Works!. Using lambda expresion. Remove by Comparing sequences that match equals.
int[] toRemove = listOfIntArray[0];
listOfIntArray.Remove(toRemove); //It works!. Remove element by exact reference.
listOfIntArray.Remove(new int[] { 2, 3 }); // Not working / References are different.
listOfIntArray.RemoveAll(IntArrayPredicate); // It works!. Same as using lambda but using method reference.
Console.WriteLine($"{nameof(listOfIntArray)} has {listOfIntArray.Count()} elements"); // Yup. 0 elements.
The reason you're not able to remove items from your list using the Remove method is that you're storing reference types in the List, but creating new references when trying to remove an item. Because reference types by default use a reference comparison (not a comparison of their fields) to determine equality, you won't be able to remove items in that way.
One way to resolve this is to create a reference to each object in the List<int[]> outside of the list creation itself. This way, you can use the existing reference as an argument to the Remove method, and, because it's referring to the same object that was added to the list, it will match and be removed:
// Here we have 'item1' and 'item2' that refer to the location of different int[]
int[] item1 = new int[] { 0, 0 };
int[] item2 = new int[] { 1, 7 };
// And now we use those references to add the int[] items to our list
List<int[]> test1 = new List<int[]>();
test1.Add(item1);
test1.Add(item2);
// Finally, we can remove an item using the same reference that we used to add it
test1.Remove(item2);
This is very clunky, however, since we now need to maintain an individual reference for every item in our list as well as the list itself.
Another way to resolve this would be to search for the item we want to remove using our own equality algorithm (rather than relying on the default equality that Remove uses). We can use FirstOrDefault to search for the first item that has a length of 2 and whose values match those that we want. It will return a reference to the item if it's found, or null if it's not found. We can use IndexOf to get the index of the item (or -1 if it's not found), and then pass that index to the RemoveAt method to remove it:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
int indexToRemove = test1.IndexOf(test1.FirstOrDefault(item =>
item.Length == 2 && item[0] == 1 && item[1] == 7));
if (indexToRemove >= 0) test1.RemoveAt(indexToRemove);
As you can see, what you're trying to do isn't super easy. As a suggestion to help you think about the problem in a different way, you might consider using a 2-dimensional array to store the sudoku grid. Normally we store the row in the first dimesion and the column in the second dimension:
int[,] grid = new int[9, 9];
You could potentially create a few of these, one to represent the puzzle solution, one to represent the puzzle shown to the user's (with just their guesses), maybe even one to store user's "notes" (if you allow them to tag a cell with possible values before committing to a guess), though that would likely need to be a string[,] or an int[,][].
Then the typical way to loop through the grid would be something like:
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
// Do something with the cell at 'row' 'col' here
// Set a value for this cell
grid[row, col] = row + col;
// Report the value of a cell
Console.WriteLine($"The value at row {row} and column {col} is {grid[row, col]}");
}
}

"System.ArgumentOutOfRangeException" on inserting of element to reserved position of List

I have the List of Count equals 2 but currently both positions are empty:
System.Diagnostics.Debug.WriteLine(paginationCollection.PagesContent.Count); // 0
System.Diagnostics.Debug.WriteLine(paginationCollection.PagesContent.Capacity); // 2
Here is, the paginationCollection is the instance of
public class PaginationCollection<Item>
{
public readonly uint PagesCount;
public List<List<Item>> PagesContent;
public PaginationCollection(
uint pagesCount,
byte numerationFrom
)
{
PagesCount = pagesCount;
PagesContent = new List<List<Item>>(numerationFrom == 0 ? (int)pagesCount : (int)pagesCount + 1);
}
}
When I try to add some items to position number 1, I get theSystem.ArgumentOutOfRangeException:
for (int pageNumber = pagesNumerationFrom; pageNumber < lastPageNumber; pageNumber++)
{
paginationCollection.PagesContent.Insert(
pageNumber, // 1 for current data
// ↓ Confirmed that GetRange operation does not cause the Exception
flatCollection.GetRange((int)elementStartingPositionForCurrentPage, (int)elementEndingPositionForCurrentPage)
);
// ...
}
From the viewpoint of logic, the position number 1 is currently empty, but the inserting operation number be available (AFAIK in C# case, the Capacity must be greater or equal to target position).
A List, among other things, offers the flexibility to create a collection of items without specifying the size at the start, it works like magic as it just adjusts the size when you keep adding items to it. Behind the scenes, a list is actually nothing else but an Array.
When we create a list with new List(); This is what happens behind the scenes.
A new array with the size 4 is created.
The list has two properties namely Count and Capacity among others.
Count: The number of items in the list, which will be 0 initially, since there will be no elements added into it
Capacity: The number of items that can be added to the list, which will be set to the size of the initial array, in this case, 4.
As you keep adding items to the list, once the Count has reached the Capacity, the list will:
Create a new array with twice the current capacity Capacity * 2 which means an array of size 8
Copy all the previous items to this new array
Destroy the old array
At the end of this cycle, Count remains 4 while Capacity becomes 8.
This whole process is repeated as long as you keep adding items to the list. The downside to this is that it takes away some performance doing all these extra things.
If we have a rough idea in advance about the number of items that the list will probably going to contain, e.g. 100, what you could then do is initialize the list like new List(100); which means the initial Capacity is going to be 100, thus as long as Count is less than a 100, all these steps won't be performed, so we get a performance improvement over it.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.insert?view=net-7.0#definition
According to the documentation, if you added an item to a position that is less than 0 or greater than Count, you'll get an ArgumentOutOfRangeException, which in your case is correct because although there is space available in the list, there are no items in there, so it complains.

Why is the .Count of a List<T>(Int32) with initial size 0?

Hi today I stumbled over a thing with the List<T>(Int32). I thought the behaviour would be the same in following examples:
1.
var myList = new List<string>(5);
myList[1] = string.Empty;
2.
var myArray= new string[5];
myArray[1] = string.Empty;
The first example fails and I get a 'System.ArgumentOutOfRangeException'. The second example works well.
So I tried .Count on the list and it says its 0, where as when I put .Length at the array it says 5.
In MSDN it says:
Initializes a new instance of the List class that is empty and has
the specified initial capacity.
I thought this means the list has the initial size I pass in. Why isn't this the case?
Thanks in advance!
Count is how much elements actually in the list, Capacity is the size of the internal data structure. It's intended to handle large list that you already know the size beforehand, so it doesn't need repeated resizing when adding.
The initial capacity refers to the internal array storage maintained by the list.
If you expect to hold 100 items and you specify 100 as initial capacity, you avoid the overhead of the internal resizing of the array (well, actually the list avoids creating a new array and copy the values from the previous one...).
Maybe now you've realized that a list (and many other collection types) are just an abstraction of arrays to provide specific semantics: lists, sets, dictionaries...
For example, a list collection with 100 items of initial capacity might add items to an internal array which already has 100 indexes/slots:
int[] array1 = new int[100];
array1[0] = 1;
// until...
array1[99] = 2;
...while a one which doesn't provide a good capacity, it may need to internally handle the insertion of 100 items this way:
int[] array2 = new int[3];
array2[0] = 1;
array2[1] = 2;
array2[2] = 3;
int[] array3 = new int[6];
array2.CopyTo(array3);
array3[3] = 4;
array3[4] = 5;
array3[5] = 6;
int[] array4 = new int[9];
array3.CopyTo(array4);
array4[6] = 7;
array4[7] = 8;
array4[8] = 9;
// and so on...
The whole internal array as list's storage already does a minimum reservation, but this is just an implementation detail. If you already know how many items you're going to add to the list, it'll be better that you provide an initial capacity.
Note that the initial capacity doesn't fix the maximum capacity of the whole list. This would defeat the purpose and semantics of lists: a collection of objects ordered by inserting order (FIFO, first-in, first-out). Once the capacity has been reached, the internal array is resized again.
Also, since lists in the higher-level are described as just object collections, you can't expect that providing an initial capacity could provide access to the internal storage indexes. The fact that there's an internal array storing collection's object is an implementation detail, you need to rely on high-level details:
// Above reason is why you CAN'T access myList[1]
var myList = new List<string>(5);
myList[1] = string.Empty;
Further details
Hopefully, now most .NET Framework source code is available online. You can take a look at List<T> source code to check yourself how it works internally:
List<T> source code

C# Add int numbers to a list while running a loop

I have tried to get the point across in the title as best as I can but basically what I want to do is add certain items to List while running a loop so I don't have to manually put them into an if statement. Let me please show an example so that I can explain properly.
Example :-
What I need is :- the first number would be 500 and that would be in index 0, then i want a loop to add 150 to the last number generated so that the int list would look like this,
index 0 = 500
index 1 = 650
index 2 = 800
index 3 = 950
Do this repeatedly until say the last number will read 2,000,000
Now I believe that this would be simple to run a loop and base it on conditions but I can only seem to figure out to run a loop that will increment the value in 1.
Hope I have explained well enough
Regards,
M
Now I believe that this would be simple to run a loop and base it on
conditions but I can only seem to figure out to run a loop that will
increment the value in 1.
This is not true, you can adjust the increment of the iterator as you wish.
var numbers = new List<int>();
for(int i=500; i<=2000000; i+=150)
{
numbers.Add(i);
}
For further information on this, please have a look here.
Just another implementation:
var result = new List<int>();
var number = 500;
do
{
result.Add(number);
number+= 150;
} while (number <= 2000000);

Can't assign value to an array

I have an array of tiles that are of the type Texture2D and want to set each one in the array to something different.
for (int i = 1; i <= columns * rows; i++)
{
m_tiles[i] = new Texture2D(m_graphicsDevice, tilewidth, tileheight);
}
It points to the error being the closing }
I don't understand how it being null when I'm trying to set it to not be null effects it. If I can never set the variable to anything then they'll always be null.
I have tried:
Texture2D[] m_tiles = new Texture2D(m_graphicsDevice, tilewidth, tileheight)[500];
But the compiler says "Cannot apply indexing with [] to and expression of type 'Microsoft.Xna.Framework.Graphics.Texture2D'"
You'll first need to initialize an array instance in order to assign values to its elements:
Preceed the for-loop with following statement:
Texture2D[] m_tiles = new Texture2D[columns * rows + 1];
Arrays indices are 0-based in C#, and afaik most .NET languages. So when using the indexer, you might want to loop from 0 .. n-1, instead of 1 .. n.
But honestly, I rarely ever still use arrays in .NET. If you have no specific reason to use an array, I would recommend to use a List<T> :
List<Texture2D> m_tiles = new List<Texture2D>();
for(;;)
{
m_tiles.Add(new Texture2D(foo, bar));
}
You need to instantiate the array first, like:
m_tiles = new Texture2D[10];
Like most other types, arrays need to be created, more specifically it needs to know how many elements you want it to have (in this case, it has 10 "slots").
You need to initialize the array with a proper dimension.
m_tiles[] may not be initialized to receive (columns * rows) elements.
So, before your loop, you should initialize the m_titles array with this size.
Texture2D[] m_tiles = new Texture2D[columns * rows];
So, if you have 1 columns and 1 rows, it will give you 1 slot (m_tiles[0]). If you have 2 columns and 2 rows you will have 4 slots (m_tiles[0],m_tiles[1],m_tiles[2],m_tiles[3]);
You should start you loop with i = 0 otherwise, the [0] won't be assigned and an exception of index out of bound will be trigged. If you really do not want to start with 0, you can increase by 1 the size of the array using (columns * rows +1).

Categories

Resources