比较 C# 中的两个列表,并使用 LINQ 或 foreach 根据条件拒绝或选择子列表



我在 C# 中有两个相同实体的列表(一个父列表和另一个可以变化的子列表),它们有很多属性,在这些属性中有两个是V_ID(不是实体的唯一 ID)和值。

我需要在两个列表之间进行比较,并从子列表中找出可以根据条件完全选择或拒绝:如果两个列表之间的V_ID相等,并且值可以为 null 或等于父列表的值。

我将无法将列表转换为字典,因为如果没有实体的主要 ID,我将无法唯一标识该项目。让我知道是否有办法通过字典做到这一点。

请帮助我如何实现这一点,我已经尝试了各种方法,包括 LINQ、for-each 等,因为子列表中的所有实体要么被完全拒绝,要么被选中。

我也是 C# 和 Linq 的新手,我提供了从我的原始源代码和各种场景示例中提取的代码示例。

public class MyEntity
{
public int ID {get; set;}
public int W_ID {get; set;}
public long ValueOfW {get; set;}
public string SampleName {get; set;}
public DateTime ModifiedBy {get; set;}
//Other Properties
}
 public List<long> MyMethod(List<MyEntity> parentInput, List<MyEntity> childInput)
{
 var parentList = new List<MyEntity>(); //Obtained from Source A which is the parent and never changes
 var childList = new List<MyEntity>();  //Obtained from Source B and converted to type MyEntity
 var mySelectedIds = new List<long>(); 
 if(parentInput.Any() && childInput.Any())
 {
    parentList = parentInput;
    childList = childInput;
    foreach(var parent in parentList)
    {
        foreach(var child in childList)
        {
            if(parent.W_ID == child.W_ID && (parent.ValueOfW == child.ValueOfW || parent.ValueOfW == 0))
                {
                    mySelectedIds.Add(child.ID);
                }
        }
    }
 }
    return mySelectedIds; //Need to do some operation after getting the IDs
}

数据示例:

家长列表

     W_ID  ValueOfW 
     ----------
     10  100
     20  200
     30  300

子列表 A:

   W_ID  ValueOfW 
    ----------
    10  100
    20  200
    30  NULL
  Expected Output: The child list A should be selected 
  as IDs are matching and the value for 30 is NULL

子列表 B

   W_ID  ValueOfW 
   ----------
    10  100
    20  200
    30  301
  Expected Output: The child list B should be selected 
  as IDs are matching and but the value for 30 is not equal

子列表 C

   W_ID  ValueOfW 
    --------
    10  100
    20  200
    30  300
    40  400
   Expected Output: The child list C should be selected 
  as IDs are matching and values match even though there is 
  extra item in the list.

为了简单起见,我要做的第一件事就是使比较成为它自己的功能。这并不重要,但它将有助于提高可读性。我不知道这种情况描述了什么,所以我就称之为TheCondition.(此外,如果条件本身存在错误,则可能更容易发现这种方式。

public bool TheCondition(MyEntity parent, MyEntity child)
{
    return parent.W_ID == child.W_ID 
        && (parent.ValueOfW == child.ValueOfW || parent.ValueOfW == 0)
}

然后,从子列表中获取所需的元素

var selected = childList.Where(child => 
    parentList.Any(parent => TheCondition(parent, child) == true)); 

指定== true只是为了使其更易于阅读。在"现实生活"中,我只会使用

var selected = childList.Where(child => 
    parentList.Any(parent => TheCondition(parent, child)));

因为该函数已经返回布尔值。

现在selected是一个IEnumerable<MyEntity>.要获取 ID 列表,

var ids = selected.Select(entity => entity.ID).ToList();

我们所说的是"从子列表中选择条件为该子项和父列表中的任何父项的条件为真。使用Any意味着,如果它确实找到了与其中一个父项的匹配项,则不需要与所有其他父项进行比较。

然后在最后一步中,我们说"从上一个实体列表中选择所有 ID",这将返回一个IEnumerable<int>,然后根据这些值创建一个新List<int>


如果我们再分解一下,这甚至会更清楚一点。我不一定会每次都这样做,但它可以更容易理解。(起初我为此苦苦挣扎 - 也许你会比我更快地赶上。

public bool TheCondition(MyEntity parent, MyEntity child)
{
    return parent.W_ID == child.W_ID 
        && (parent.ValueOfW == child.ValueOfW || parent.ValueOfW == 0)
}
public bool ChildMatchesAnyParent(MyEntity child, IEnumerable<MyEntity> parents)
{
    return parents.Any(parent => TheCondition(parent, child);
}
var selected = childList.Where(child => ChildMatchesAnyParent(child, parentList));
var ids = selected.Select(entity => entity.ID).ToList();

您也可以将它们链接在一起列出,将它们组合成一个语句。

var ids = childList.Where(child => ChildMatchesAnyParent(child, parentList))
    .Select(entity => entity.ID).ToList();

对我来说,我需要了解它是如何单独工作的,然后更容易开始将它们组合在一起。但有时为了可读性,将它们分开还是好的。

实现

此目的的一种方法是使用 LINQ 查询语言语句。

var childArray = child.ToArray();               // Convert to an array to enumerate once
return !(from e in parent                       // Get all the parents
    from c in childArray                        // cross join with children
    where e.W_ID == c.W_ID                      // filter those with only matching ID
    where e.Value != c.Value && c.Value != null // filter those based on your condition
    select e).Any();                           

请注意布尔值 NOT ( ! )。如果过滤后有任何结果,则应拒绝该子项。

最新更新