【问题标题】:Find, in a list, all arrays whose first element is the same as the ones that match a condition在列表中查找第一个元素与匹配条件的数组相同的所有数组
【发布时间】:2018-04-30 13:35:38
【问题描述】:

这是一个很难命名的问题。

在 C# 中,我有一组 int[,] 数组存储在 List<int[,]> paths 中,每个数组都包含一组坐标以形成路径。 一个例子是{ {0,0}, {0,1}, {1,1}, {2,1} }

现在,我想在paths 中保留与匹配条件的所有路径的第一个索引具有相同第一个索引的所有路径。

为了更好地说明我的意思,假设我得到了所有奇数长度的路径:

paths.Where(x => x.GetLength(0) % 2 == 1).ToList();

假设这会返回一个列表,其中包含一些数组,例如,这些数组的第一个坐标是 {0,0} 或 {0,1}。我希望 pathsbe paths.Where( x=> x 的第一个坐标是 {0,0} 或 {0,1})。我怎样才能做到这一点?

希望我的意思可以理解。

【问题讨论】:

  • 既然这些是路径,而且您总是有 2 个,您是否考虑过拥有一个具有两个属性的坐标类?
  • 你的意思是像x[0][0] == 0 && x[0][1]== 1这样的吗?
  • @NevilleNazerane 如果有其他选择就不是最好的了,因为我已经在代码的其他部分使用了这个path 列表

标签: c# arrays list multidimensional-array


【解决方案1】:

如果您打算使用当前的数据结构,那么您可以这样做,但语法不会很漂亮。这基本上就像 A. Milto 在他的回答中建议的那样,除了您需要边界检查以避免在空路径的情况下引发异常。因此,如果您像这样定义路径:

var arrayPaths = new List<int[,]>();
arrayPaths.Add(new[,] { { 0, 0 }, { 0, 1 }, { 1, 1 }, { 2, 1 } });  // Include: starts with (0, 0)
arrayPaths.Add(new[,] { { 0, 1 }, { 0, 1 }, { 1, 1 }, { 2, 1 } });  // Include: starts with (0, 1)
arrayPaths.Add(new[,] { { 1, 0 }, { 0, 1 }, { 1, 1 }, { 2, 1 } });  // Exclude: starts with (1, 0)
arrayPaths.Add(new int[0,0]);                                       // Exclude: has no data

那么从 (0, 0) 或 (0, 1) 开始的路径子集是:

arrayPaths.Where(p => 
    p.GetUpperBound(0) >= 0 && 
    p.GetUpperBound(1) >= 1 && 
    (
        (p[0, 0] == 0 && p[0, 1] == 0) || 
        (p[0, 0] == 0 && p[0, 1] == 1)
    ));

Neville Nazerane 在他的评论中提出了一个很好的建议:使用除整数数组之外的数据结构来表示一个点应该会使代码更容易理解。例如,假设您这样定义坐标:

public struct Coordinate
{
    public Coordinate(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; }
    public int Y { get; }

    public bool Equals(int x, int y) => 
        X == x && Y == y;
}

然后你可以像这样定义上面给出的路径集:

var objectPaths = new List<List<Coordinate>>();
objectPaths.Add(new List<Coordinate> { new Coordinate(0, 0), new Coordinate(0, 1), new Coordinate(1, 1), new Coordinate(2, 1) });
objectPaths.Add(new List<Coordinate> { new Coordinate(0, 1), new Coordinate(0, 1), new Coordinate(1, 1), new Coordinate(2, 1) });
objectPaths.Add(new List<Coordinate> { new Coordinate(1, 0), new Coordinate(0, 1), new Coordinate(1, 1), new Coordinate(2, 1) });
objectPaths.Add(new List<Coordinate>());

现在您感兴趣的路径子集是:

objectPaths.Where(p => p.Count > 0 && (p[0].Equals(0, 0) || p[0].Equals(0, 1)));

如果您想要更简洁的语法来指定代码中的路径,那么您可以考虑使用一个非常简单的类来表示路径。例如:

public class Path : List<Coordinate>
{
    public Path() { }

    public Path(params (int x, int y)[] coordinates) =>
        AddRange(coordinates.Select(c => new Coordinate(c.x, c.y)));
}

现在您可以将路径集定义为:

var paths = new List<Path>();
paths.Add(new Path((0, 0), (0, 1), (1, 1), (2, 1)));
paths.Add(new Path((0, 1), (0, 1), (1, 1), (2, 1)));
paths.Add(new Path((1, 0), (0, 1), (1, 1), (2, 1)));
paths.Add(new Path());

并且选择你想要的子集的语法和以前一样。

【讨论】:

    【解决方案2】:

    像这样:

    var filteredPaths = paths.Where(x => x[0, 0] == 0 && x[0, 1] == 0  ||  x[0, 0] == 0 && x[0, 1] == 1);
    

    或者,如果您希望继续使用相同的集合类型:

    List<int[,]> filteredPaths = paths.Where(x => x[0, 0] == 0 && x[1, 0] == 0  ||  x[0, 0] == 0 && x[1, 0] == 1).ToList();
    

    【讨论】:

      【解决方案3】:

      假设下面的列表代表您的多维元素,这是一个解决方案:

      List<short[,]> paths = new List<short[,]>
                          {
                              new short[3, 2] { { 0, 0 }, { 4, 5 }, { 6, 7 } },
                              new short[3, 2] { { 0, 1 }, { 8, 9 }, { 10, 11 } },
                              new short[3, 2] { { 1, 1 }, { 1, 3 } ,{ 6, 1 } },
                              new short[3, 2] { { 2, 1 }, { 3, 5 }, { 7, 7 } }
                          };
      

      定义标准,即:

      short[,] firstCriteria = new short[1, 2] { { 0, 0 } };
      short[,] secondCriteria = new short[1, 2] { { 0, 1 } };
      

      定义一个扩展方法,它应该使我们能够截断多维数组到仅用于过滤的第一个坐标。

      static class Helper
      {
              public static IEnumerable<short> SliceRow(this short[,] array, short row)
              {
                  for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
                  {
                      yield return array[row, i];
                  }
              }
       }
      

      那么你可以这样做:

      var resutSet = 
                   paths.Where(e => e.SliceRow(0).SequenceEqual(firstCriteria.Cast<short>()) ||
                         e.SliceRow(0).SequenceEqual(secondCriteria.Cast<short>())).ToList();
      

      resultSet 现在将包含两个满足给定条件的多维数组,即:

      { { 0, 0 }, { 4, 5 }, { 6, 7 } ,
        { 0, 1 }, { 8, 9 }, { 10, 11 } }
      

      【讨论】:

        猜你喜欢
        • 2015-05-23
        • 2016-02-21
        • 1970-01-01
        • 2016-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多