【问题标题】:Removing an array of int from a list of type int array从 int 类型数组的列表中删除一个 int 数组
【发布时间】:2021-11-20 21:48:41
【问题描述】:

我打算有一个 List<int[]> 类型的字段,它包含一些 int 数组(在 Unity 中用于记录一些网格位置),大致如下:

{
 {0, 0},
 {0, 1},
 {0, 2}
}

但是当我尝试从这个列表中删除元素时,这样做似乎有些困难:

int[] target = new int[] {0, 0}; 
// Simplified, in the actual code I have to do some calculations. 
// But during debug, I confirmed that the same array I want to remove 
// is in the intArrayList

intArrayList.Remove(target);

// {0, 0} seems to be still here

这应该发生吗?如果是这样,我该如何解决?

【问题讨论】:

  • 那些是内存中不同的对象。这就是删除不起作用的原因。这适用于引用类型,例如整数或字符串,但由于目标是数组(引用类型),remove 找不到该项目。我认为找到索引并按索引删除是最好的选择。
  • 尝试阅读这个答案,可能有用:stackoverflow.com/questions/10018957/…
  • 您的列表是否必须是普通的旧数组?如果不是,您可以创建一个准数组类并覆盖 GetHashCode (可能 xor ^ 所有数字)和 Equals (实际上检查每个元素的相等性)。然后 List.Remove 就可以了。
  • “但在调试过程中,我确认我想删除同一个数组”这看起来并不正确,尤其是基于已接受的答案。请注意您观察/报告的内容:“相同的数组”和“具有相同值的数组”是非常不同的东西 - 即问题中显示的示例确实暗示 intArrayList = new List<int[]>(target, new[]{0,1}, new[]{0,2}); 但接受了答案提示。

标签: c# arrays list unity3d


【解决方案1】:

问题是您正在删除同一列表的不同实例。由于 C# 数组使用默认的相等检查器,因此实例需要相同才能删除另一个数组。

快速解决方法是编写自己的方法,首先在列表中搜索适当的数组,然后删除该索引处的项目:

var target =  new int[] {0, 0}; 
var indexToRemove = intArrayList.FindIndex(a => a.SequenceEqual(target));
if (indexToRemove >= 0) {
    intArrayList.RemoveAt(indexToRemove);
}

一个好的解决方法是停止使用“裸”数组:将其包装到您自己的类中,并使用适当的比较语义,并改用该类。这将使您的代码更具可读性,让您更好地控制进入数组的内容,并让您在必要时保护数组不被写入。它还允许您使用原始的删除代码,这是您在数组顶部编写有意义的包装器所获得的其他好处之外的一个小奖励。

【讨论】:

  • 老兄,这个 SequenceEquals 太棒了。
【解决方案2】:

使用正确的数据结构!

你所拥有的有点像XY Problem。您在尝试的解决方案中遇到了问题,该解决方案使用错误的数据结构来实现您实际尝试实现的目标。

如果这与您所说的 Unity 网格位置有关,根本不要使用 int[]

而不是简单地使用Vector2Int,它已经为两个耦合的int值(坐标)提供了一个结构,并实现了所有必要的接口以成功比较它是否相等:

List<Vector2Int> yourList = new List<Vector2Int>()
{
    new Vector2Int(0, 0),
    new Vector2Int(0, 1),
    new Vector2Int(0, 2),
    ...
}

var target = new Vector2Int(0, 1);
yourList.Remove(target);

由于Vector2Int 实现了IEquatable&lt;Vector2Int&gt;GetHashCode,因此可以隐式地对列表和字典进行此类操作。

【讨论】:

    【解决方案3】:

    您正在尝试通过 ref 删除数组,并且很可能您的意图是按值删除它。

    这应该可行:

    intArrayList.RemoveAll(p => p[0] == 0 && p[1] == 0);
    

    另一个选择是使用记录而不是 int[2] 数组,因为它们具有值相等的内置实现

    record GridPosition(int X, int Y);
    //...
    List<GridPosition> intArrayList = new();
    intArrayList.Add(new GridPosition(0, 0));
    intArrayList.Add(new GridPosition(1, 0));
    
    var target = new GridPosition(0, 0);
    intArrayList.Remove(target);
    Assert.AreEqual(1, intArrayList.Count);
    

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 1970-01-01
      • 2016-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-14
      • 2015-02-22
      相关资源
      最近更新 更多