Add from one list to another - c#

I have been trying to 'transport' the first two elements from list A to list B without copying them.
At the start, list A has four int values. In the end I want List A and B to both have 2 int values.
I'm trying something like this:
int a = 1;
int b = 2;
int c = 3;
int d = 4;
TestA.Add(a);
TestA.Add(b);
TestA.Add(c);
TestA.Add(d);
for (int i=0; i<2; i++)
{
TestB.AddRange(TestA[i]);
}
I get a IEnummerable conversion error. I'm sure I'm doing it in a very naive way, and I'd appreciate some help here. Thanks.

What's wrong with simple Take/Skip combination?
TestB = TestA.Take(2).ToList();
TestA = TestA.Skip(2).ToList();
Enumerable.Take - takes N elements from beginning of the collection.
Enumerable.Skip - skips N elements from beginning of the collection and takes all others.

Related

List of Lists in C#, problem with indexes

In C#, I create a list of lists and try to access/modify the elements. There is a problem in that it seems that an operation (e.g. adding a constant) seems to apply not only to the wanted index but to all elements.
Here is the piece of code:
List<List<double>> D = new List<List<double>>();
List<double> ttmp = new List<double>(new double[256]);
for (int i = 0; i < 100; i++)
{
D.Add(ttmp);
}
for (int i = 0; i < 100; i++)
{
D[i][0] = D[i][0] + 1;
}
D is a list of 100 lists, each of size 256. It initially contains only zeroes. In the second loop, I ask that the first element of every of the 100 lists be incremented by one.
As a results, the entire "matrix" is filled with ones, i.e. not only D[0][0], D[1][0] ... D[99][0], but also D[0][1], D[0][2] , etc.
Why is that?
NB: the C++ equivalent with vector<vector<double>> works perfectly fine...
When code is executed, result is not that
D[0][0], D[1][0] ... D[99][0], but also D[0][1], D[0][2] are modified.
Result is that inner lists have [0] element equal to 100.
Why so? Because you created one list, and added it 100 times into D. But that is the same list - when you modify it, you modify all instances (because this is reference data type).
Change it instead to:
List<List<double>> D = new List<List<double>>();
for (int i = 0; i < 100; i++)
{
D.Add(new List<double>(new double[256]));
}
foreach (var innerList in D)
{
innerList[0]++;
}

How to uodate array inside a for loop and add it to a list

I am trying to update an array and add it to a list if a certain condition is true. As you can see in my code the array "rows" is updated every time inside the if condition, and the it is added to "checkList".
The problem is that when I iterate through the list to check the values, it seems that only the last value of rows has been added in every entry in the list.
Here is some code to explain
int[] rows = new int[2];
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
rows[0] = i;
rows[1] = j;
checkList.Add(rows);
}
}
}
foreach (var row in checkList)
{
Console.WriteLine(row[0] + " " + row[1]);
}
Output:
I hope someone can explain this. Thanks
Most object types in .NET (including arrays) are passed by reference, so checkList.Add(rows); adds a reference to the same array to the list, multiple times.
Instead, you'll want to create a new array instance every time:
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
checkList.Add(new int[]{ i, j });
}
}
}
I believe the issue here is that when you are
checkList.Add(rows);
You are adding a reference to the rows array every time to the list, not a separate copy of it. This leads to your current behaviour.
A solution would be to instantiate the array inside the loop, so a new array is created every iteration.
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
int[] rows = new int[2];
rows[0] = i;
rows[1] = j;
checkList.Add(rows);
}
}
}
As a supplement to Matthias answer, one of the things that's perhaps not easy to appreciate about C# is that most variables you have and use are merely a reference to something else. When you assign some variable like this:
int[] rows = new int[2];
C# creates some space in memory to keep an array of 2 integers, it attaches a reference to it, and that thing becomes your variable that you use, named rows. If you then do:
int[] rows2 = rows;
It doesn't clone the memory space used and create a new array, it just creates another reference attached to the same data in memory. If the data were a dog, it now has 2 leads attached to its collar but there is still only one dog. You can pull on either lead to urge the dog to stop peeing on a car, but it's the same dog you're affecting.
Array/list slots are just like variables in this regard. To say you have:
List<int[]> checkList = new List<int[]>();
Means declare a list where each of its slots are a variable capable of referring to an int array. It's conceptually no different to saying:
int[] checkList0 = row;
int[] checkList1 = row;
int[] checkList2 = row;
int[] checkList3 = row;
It's just that those numbers are baked into the name, whereas a list permits you a way of varying the name programmatically (and having more than 4 slots):
checkList[0] = row;
checkList[1] = row;
checkList[2] = row;
checkList[3] = row;
checkList[0] is conceptually the entire variable name, just like checkList0 is a variable name, and remember that this is hence just another variable that is just a reference to that same array in memory.
By not making a new array each time, you attached every variable slot in the list to the same array in memory, and thus you ended up with something in memory that looks like:
The black is the list, the blue is the array. Every list slot is just a reference to the same array. You might have changed the numbers in the array 200 times, but at the end of the oepration, because there was only ever one array, you only see the final set of numbers you wrote into the array. You might have attached 20 leads to your dog and pulled each of them once, but it's still just the same dog that has 20 times been stopped from peeing on 20 cars.
Matthias answer works (and is how it should be done) because you concretely make a new array each time
Numbers in blue are fabricated and not intended to represent the answers you should see printed; the concept being explained is that of linking to new array objects in memory
You'd be forgiven for thinking that a clone would be made, bcause it is for int. int is a value type, whcih means the value is copied when it's used:
int x = 1;
int y = x;
y = y + 1;
y is now 2, but x is still 1. It'd be pretty hard work to write C# if it wasn't this way i.e. if every time you incremented some int variable, every other variable that had touched the variable that it came from was also affected.. So I think it's perhaps intrinsically reasonable to assume that whenever an assignment of anything is made, changes that affect the value of the assigned variable don't affect earlier iterations of it.. but that's not the case. There's this clear divide between value types (types whose data is copied/cloned when they're assigned) and reference types (types whose data is not copied/cloned). While int is a value type (cloned), an int[] is a reference type (not cloned)
..and that's something you'll really need to get down with and remember
Roll on the what's ref/out for? query :D

Order of operations when working with array index

Consider this loop:
int[] myArray = new int[10];
int myIndex = 0;
for (int i = 0; i < 10; i++)
{
myArray[myIndex++] = myIndex;
Console.WriteLine(myArray[i]);
}
This yields:
1
2
3
...
Because myIndex is post-incremented, and the right side is evaluated first, shouldn't the array index 0 contain 0?
Can someone explain this order-of-operations misunderstanding for me?
The right side isn't necessarily evaluated first. Similar to:
foo.Bar.Baz = a + b;
In the above code, foo.Bar is evaluated first, then a + b, then the set_Baz method is called to set the Baz property to whatever is evaluated on the right.
So in your code, if you break it into pieces, it looks like this:
var index = i;
// post-incremented in the original code means this comes after the line above,
// but not after the line below it.
i += 1;
myArray[index] = i;
first run:
myArray[myIndex++] = myIndex;
* *
| |
zero one
myIndex++ gets executed after myArray[myIndex++], but any subsequent calls with have the already incremented variable.
The myIndex++ is executing before the value is being set because the array index takes precident so it knows what array index to set the value to.
The...
myArray[myIndex++] = myIndex;
...is equivalend to...
int tmp = myIndex;
++myIndex;
myArray[tmp] = myIndex;
The myIndex++ is evaluated first, followed by the left side and finally the assign operator, according to precedence

What's the best way to implement an unfixed multi-deminsional array in C#.NET?

For example: an array of varying-length arrays of integers.
In C++, we are used to doing things like:
int * * TwoDimAry = new int * [n] ;
for ( int i ( 0 ) ; i < n ; i ++ )
{
TwoDimAry[i] = new int [i + n] ;
}
In this case, if n == 3 then the result would be an array of three pointers to arrays of integers, and would appear like this:
http://img263.imageshack.us/img263/4149/multidimarray.png
Of course, .NET arrays are managed collections, so you don't have to deal with the manual allocation/deletion.
But declaring:
int[][] TwoDimAry ;
... in C# does not appear to have the same effect - namely, you have to innitialize ALL of the sub-arrays at the same time, and they have to be the same length.
I need my sub-arrays to be independent of each-other, as they are in native C++.
What's the best way to implement this using managed collections? Are there any drawbacks I should be aware of?
Like C++, you need to initialize every subarray in an int[][].
However, they don't need to have the same length. (That's why it's called a jagged array)
For example:
int[][] jagged1 = new int[][] { new int[1], new int[2], new int[3] };
Your C++ code can be translated directly to C#:
int[][] TwoDimAry = new int[n][];
for(int i = 0; i < n; i++) {
TwoDimAry[i] = new int[i + n];
}
Here is an example with a jagged array initialized with 1, 2, 3, .. elements for each row
int N = 20;
int[][] array = new int[N][]; // First index is rows, second is columns
for(int i=0; i < N; i++)
{
array[i] = new int[i+1]; // Initialize i-th row with 'i' columns
for( int j = 0; j <= i; j++)
{
array[i][j] = N*j+i; // Set a value for each column in the row
}
}
I have use this enough to know that there aren't many drawbacks overall. Hybrid appraches with List<int[]> or List<int>[] also work.
In .Net, most of the time you don't want to use arrays this way at all. This is because in .Net, arrays are thought of as a different animal from a collection. Managed, yes. Collection? Well, maybe, but it confuses terms because that means something special. If you want a collection (hint: most of the time you do), look in the Systems.Collections namespace, particularly Systems.Collections.Generic. It sounds like you really want either a List<List<int>> or a List<int[]>.

Which collection type to use?

I have a scenario where I have a list of classes, and I want to mix up the order. For example:
private List<Question> myQuestions = new List<Question>();
So, given that this is now populated with a set of data, I want to mix up the order. My first thought was to create a collection of integers numbered from 1 to myQuestions.Count, assign one at random to each question and then loop through them in order; however, I can’t seem to find a suitable collection type to use for this. An example of what I mean would be something like this:
for (int i = 0; i <= myQuestions.Count -1; i++)
tempCollection[i] = myQuestions[rnd.Next(myQuestions.Count-1)];
But I’m not sure what tempCollection should be – it just needs to be a single value that I can remove as I use it. Does anyone have any suggestions as to which type to use, or of a better way to do this?
I suggest you copy the results into a new List<Question> and then shuffle that list.
However, I would use a Fisher-Yates shuffle rather than the one you've given here. There are plenty of C# examples of that on this site.
For example, you might do:
// Don't create a new instance of Random each time. That's a detail
// for another question though.
Random rng = GetAppropriateRandomInstanceForThread();
List<Question> shuffled = new List<Question>(myQuestions);
for (int i = shuffled.Count - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
Question tmp = shuffled[i];
shuffled[i] = shuffled[swapIndex];
shuffled[swapIndex] = tmp;
}
You could use Linq and order by a random value:
List<string> items = new List<string>();
items.Add("Foo");
items.Add("Bar");
items.Add("Baz");
foreach (string item in items.OrderBy(c => Guid.NewGuid()))
{
Console.WriteLine(item);
}
temp Collection should be same type as myQuestions.
I would also suggest a change in your code:
for (int i = 0; i <= myQuestions.Count -1; i++)
to
for (int i = 0; i < myQuestions.Count; i++)
Does the same thing, but this is how most programers do it so it will make your code simpler to read.

Categories

Resources