简体   繁体   English

如何在 for 循环中更新数组并将其添加到列表中

[英]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".正如您在我的代码中看到的那样,每次在 if 条件内都会更新数组“rows”,并将其添加到“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: Output:

在此处输入图像描述

I hope someone can explain this.我希望有人能解释一下。 Thanks谢谢

Most object types in .NET (including arrays) are passed by reference , so checkList.Add(rows); .NET 中的大多数 object 类型(包括数组)都是通过引用传递的,所以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.作为对 Matthias 答案的补充,关于 C# 可能不容易理解的一件事是,您拥有和使用的大多数变量只是对其他事物的引用。 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 . C# 在 memory 中创建一些空间来保留 2 个整数的数组,它附加一个对它的引用,并且那个东西成为你使用的变量,命名为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.它不会克隆使用的 memory 空间并创建一个新数组,它只是创建另一个附加到 memory 中相同数据的引用。 If the data were a dog, it now has 2 leads attached to its collar but there is still only one dog.如果数据是一只狗,现在它的项圈上有 2 条引线,但仍然只有一只狗。 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 .方法声明一个列表,其中每个插槽都是能够引用 int 数组的变量 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):只是这些数字被包含在名称中,而列表允许您以编程方式更改名称(并且具有 4 个以上的插槽):

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. checkList[0]在概念上是整个变量名,就像checkList0是一个变量名一样,请记住,这只是另一个变量,它只是对 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:通过不每次都创建一个new数组,您将列表中的每个变量插槽附加到 memory 中的同一数组,因此您最终在 memory 中得到了一些如下所示的内容:

在此处输入图像描述

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.您可能已经将数组中的数字更改了 200 次,但在操作结束时,因为只有一个数组,您只能看到您写入数组的最后一组数字。 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.您可能已将 20 根导线连接到您的狗身上,并且每根都拉了一次,但它仍然是同一只狗,它已经 20 次被阻止在 20 辆汽车上撒尿。

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正在解释的概念是链接到 memory 中的新数组对象


You'd be forgiven for thinking that a clone would be made, bcause it is for int .你会认为会制作一个克隆是可以原谅的,因为它是针对 int 的 int is a value type, whcih means the value is copied when it's used: int是一个值类型,这意味着该值在使用时被复制:

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 ie 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. y现在是 2,但x仍然是 1。如果不是这样写 C# 将是相当困难的工作,即如果每次增加一些int变量,所有其他变量都触及它来自的变量也受到影响..所以我认为假设无论何时进行任何分配,影响分配变量值的更改不会影响它的早期迭代,这可能在本质上是合理的。但事实并非如此。 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)虽然int是值类型(克隆),但int[]是引用类型(未克隆)

..and that's something you'll really need to get down with and remember ..这是你真正需要接受并记住的事情


Roll on the what's ref / out for?滚动ref / out是为了什么? query:D查询:D

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM