简体   繁体   English

比较一个最佳列表是否是C#中另一个列表的子集的最佳方法

[英]Best approach to compare if one list is subset of another in C#

I have the below two classes: 我有以下两节课:

public class FirstInner
{
    public int Id { get; set; }
    public string Type { get; set; }
    public string RoleId { get; set; }
}
public class SecondInner
{
    public int Id { get; set; }
    public string Type { get; set; }            
}

Again, there are lists of those types inside the below two classes: 同样,在以下两个类别中有这些类型的列表:

public class FirstOuter
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public List<FirstInner> Inners { get; set; }
}
public class SecondOuter
{
    public int Id { get; set; }
    public string Name { get; set; }         
    public List<SecondInner> Inners { get; set; }
}

Now, I have list of FirstOuter and SecondOuter . 现在,我有FirstOuterSecondOuter列表。 I need to check if FirstOuter list is a subset of SecondOuter list. 我需要检查,如果FirstOuter列表的一个子集SecondOuter列表。

Please note: 请注意:

  1. The names of the classes cannot be changed as they are from different systems. 类名不能更改,因为它们来自不同的系统。
  2. Some additional properties are present in FirstOuter but not in SecondOuter . FirstOuter中存在一些其他属性,但FirstOuterSecondOuter When comparing subset, we can ignore their presence in SecondOuter . 比较子集时,我们可以忽略它们在SecondOuter的存在。
  3. No.2 is true for FirstInner and SecondInner as well. No.2对于FirstInnerSecondInner也是如此。
  4. List items can be in any order--- FirstOuterList[1] could be found in SecondOuterList[3] , based on Id, but inside that again need to compare that FirstOuterList[1].FirstInner[3] , could be found in SecondOuterList[3].SecondInner[2] , based on Id. 表项可以按任何顺序--- FirstOuterList[1]可以在找到SecondOuterList[3]根据ID,但是这里面需要再次来比较FirstOuterList[1].FirstInner[3]可以在发现SecondOuterList[3].SecondInner[2] ,基于ID。

I tried Intersect, but that is failing as the property names are mismatching. 我尝试了“相交”,但是由于属性名称不匹配而失败。 Another solution I have is doing the crude for each iteration, which I want to avoid. 我要解决的另一种解决方案是for each迭代都使用粗略for each ,这是我想避免的。

Should I convert the SecondOuter list to FirstOuter list, ignoring the additional properties? 如果我的转换SecondOuter列表FirstOuter列表,忽略了附加属性?


Basically, here is a test data: 基本上,这是一个测试数据:

var firstInnerList = new List<FirstInner>();
firstInnerList.Add(new FirstInner
{
    Id = 1,
    Type = "xx",
    RoleId = "5"
});
var secondInnerList = new List<SecondInner>();
secondInner.Add(new SecondInner
{
    Id = 1,
    Type = "xx"
});
var firstOuter = new FirstOuter 
{
    Id = 1,
    Name = "John",
    Title = "Cena",
    Inners = firstInnerList
}
var secondOuter = new SecondOuter
{
    Id = 1,
    Name = "John",
    Inners = secondInnerList,
}
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };

Need to check if firstOuterList is part of secondOuterList (ignoring the additional properties). 需要检查是否firstOuterList是部分secondOuterList (忽略额外属性)。

So the foreach way that I have is: 所以我拥有的foreach方式是:

foreach (var item in firstOuterList)
        {
            var secondItem = secondOuterList.Find(so => so.Id == item.Id);
            //if secondItem is null->throw exception
            if (item.Name == secondItem.Name)
            {
                foreach (var firstInnerItem in item.Inners)
                {
                    var secondInnerItem = secondItem.Inners.Find(sI => sI.Id == firstInnerItem.Id);
                    //if secondInnerItem is null,throw exception
                    if (firstInnerItem.Type != secondInnerItem.Type)
                    {
                        //throw exception
                    }
                }
            }
            else
            {
                //throw exception
            }
        }
        //move with normal flow

Please let me know if there is any better approach. 请让我知道是否有更好的方法。

First, do the join of firstOuterList and secondOuterList 首先,执行firstOuterList和secondOuterList的联接

bool isSubset = false;
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };

var jointOuterList = firstOuterList.Join(
      secondOuterList,
      p => new { p.Id, p.Name },
      m => new { m.Id, m.Name },
      (p, m) => new { FOuterList = p, SOuterList = m }
);

if(jointOuterList.Count != firstOuterList.Count)
{
      isSubset = false;
      return;
}

foreach(var item in jointOuterList)
{
      var jointInnerList = item.firstInnerList.Join(
                 item.firstInnerList,
                 p => new { p.Id, p.Type },
                 m => new { m.Id, m.type },
                 (p, m) => p.Id
      );

      if(jointInnerList.Count != item.firstInnerList.Count)
      {
                isSubset = false;
                return;
      }
}

Note: I am assuming Id is unique in its outer lists. 注意:我假设ID在其外部列表中是唯一的。 It means there will not be multiple entries with same id in a list. 这意味着列表中不会有多个具有相同ID的条目。 If no, then we need to use group by in above query 如果否,那么我们需要在上面的查询中使用分组

I think to break the question down.. 我想把问题分解。

  • We have two sets of Ids, the Inners and the Outers. 我们有两组ID,即Inners和Outers。
  • We have two instances of those sets, the Firsts and the Seconds. 我们有这些集合的两个实例,第一和第二。
  • We want Second's inner Ids to be a subset of First's inner Ids. 我们希望Second的 内部 ID是First的 内部 ID的子集。
  • We want Second's outer Ids to be a subset of First's outer Ids. 我们希望Second的 外部 ID是First的 外部 ID的子集。

If that's the case, these are a couple of working test cases: 如果是这样,这些是几个工作测试用例:

    [TestMethod]
    public void ICanSeeWhenInnerAndOuterCollectionsAreSubsets()
    {
        HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
        HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
        HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
        HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());

        bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
        bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);

        Assert.IsTrue(isInnerSubset);
        Assert.IsTrue(isOuterSubset);
    }

    [TestMethod]
    public void ICanSeeWhenInnerAndOuterCollectionsAreNotSubsets()
    {
        HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
        HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
        HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
        HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());

        firstInnerIds.Clear();
        firstInnerIds.Add(5);
        firstOuterIds.Clear();
        firstOuterIds.Add(5);

        bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
        bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);

        Assert.IsFalse(isInnerSubset);
        Assert.IsFalse(isOuterSubset);
    }

   private List<FirstOuter> GetFirstOuterList()  { ... }

   private List<SecondOuter> GetSecondOuterList()  { ... }

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

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