在列表中查找其第一个元素与条件匹配的所有数组

时间:2017-11-16 21:30:35

标签: c# arrays list multidimensional-array

这个问题非常难以解决。

在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} )。我怎样才能做到这一点?

希望我的意思是可以理解的。

3 个答案:

答案 0 :(得分: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());

选择所需子集的语法与之前相同。

答案 1 :(得分:0)

像这样:

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();

答案 2 :(得分:0)

如果下面的列表代表你的多维元素,那么这是一个可以解决的问题:

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 } }