C#/Unity/Linq - 如何检查列表列表是否包含特定的另一个列表?

C# / Unity / Linq - How to check if a list of lists contains a specific another list?

我有一个这样的整数列表:

    public List<List<int>> Paths = new List<List<int>>
    {
        new List<int>{0,1 },
        new List<int>{1,2 },
        new List<int>{1,3 },
        new List<int>{2,3 },
        new List<int>{2,4 },
        new List<int>{3,4 },
        new List<int>{4,5 },
    };

我有一条路径,它只是一个整数列表:

List<int> path = new List<int>{4,5};

如何检查 Paths 是否包含 path? 我试过 if(Paths.Contains(path)) 并且它总是产生 false,即使我知道我在那里有一个 {4, 5} 的列表。

我正在做一个统一的项目,我读到一些可以使用 linq 完成的魔法,所以我在标题主题中标记了它以供将来的 google 用户使用。 ;)

非常感谢您的帮助!

编辑: 我想出了这个临时解决方案,但我觉得它可以做得更优雅:

        public bool CheckIfPathsHaveConnection(List<int> connection)
        {
            bool hasElement = false;
            foreach(List<int> path in Paths)
            {
                if(path[0] == connection[0] && path[1] == connection[1])
                {
                    hasElement = true;
                    break;
                }
                else
                {
                    hasElement = false;
                }
            }
            return hasElement;
        }

编辑2: 谢谢大家的回复,我真的很感激你的努力。每个答案都很有帮助并且值得作为解决方案,不幸的是我只能选择一个作为解决方案,所以我选择了解释最多的一个。

尝试if (Paths.Any(x => x[0] == path[0] && x[1] == path[1]))

如果你想要一个 linq 解决方案,你可以使用 Any() and All():

的组合
var containsPath = Paths.Any(p => p                 // any sub-list in 'Paths'
                           .All(q =>                // all elements of sub-list
                               path.Contains(q)));  // are contained in 'path'

如果你想知道现有路径的索引,试试这个

    var index = IfExist(paths,path);
    
    var exist = index >= 0;
    
    public int IfExist(List<List<int>> paths, List<int> path)
    {
        for (int i = 0; i < paths.Count; i++)
            if (paths[i][0] == path[0] && (paths[i][1] == path[1])) return i;
         
         return -1;
    }
if(Paths.Contains(path))

在你的情况下 returns 总是 false 因为 List<T> 是一个 class => 引用类型并且你检查了引用相等性(它需要完全相同列表的实例),但你创建了一个 new

对于实际列表和更多一般情况,您可以使用

using System.Linq;

...

// If you use array or list doesn't matter for Linq / IEnumerable
var index = paths.FindIndex(p => p.SequenceEqual(new []{1, 2});
if(index >= 0)
{
    ...
}

returns 是第一个遇到的具有相同顺序的相同项目的列表的索引,或者 -1 如果找到 none。


但是,如果总是只有两个项目,那么我根本不会使用列表,而是使用 IEquatable and especially GetHashCode 进行适当的实现(用于任何基于散列的集合,如 DictionaryHashSet 等)例如

public class Path : IEquatable<Path>
{
    public int Start;
    public int End;

    public Path(int start, int end)
    {
        Start = start;
        End = end;
    }

    public override int GetHashCode()
    {
        return Start.GetHashCode() ^ End.GetHashCode();
    }

    public bool Equals(Path path)
    {
        return path.Start == Start && path.End == End;
    }

    public override bool Equals(object obj)
    {
        if (obj == null || ! (obj is Path path))
            return false;
        else
            return Equals(path);
    }

    public static bool operator == (Path a, Path b)
    {
        if (((object)a) == null || ((object)b) == null)
            return object.Equals(a, b);

        return a.Equals(b);
    }

    public static bool operator != (Path a, Path b)
    {
        if (((object)a) == null || ((object)b) == null)
            return ! object.Equals(a, b);

        return ! (a.Equals(b));
    }
}

然后你可以简单地拥有一个

public List<Path> Paths = new List<Path>
{
    new Path (0,1),
    new Path (1,2),
    new Path (1,3),
    ....
}

并在完全不使用 Linq 的情况下获取索引

// Since you now properly implemented Equals this now compares
// the values rather than the reference
var index = paths.IndexOf(new Path(1, 2));
if(index >= 0)
{
    ...
}

您想要的是测试 Paths 中的任何路径是否等于 path:

var ans = Paths.Any(p => p.SequenceEqual(path));