简体   繁体   English

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

[英]Compare two list in C# and reject or select the child list based on conditions using LINQ or foreach

I have two lists of same entity in C# (one parent list and another child list which can vary) which has lot of properties and out of those properties two are V_ID (not the unique ID of the entity) and value. 我在C#中有两个相同实体的列表(一个父列表和另一个子列表可能会有所不同),它们具有很多属性,其中两个是V_ID(不是实体的唯一ID)和值。

I need to compare between two lists and find out from the child list can be selected completely or rejected based on the condition : If the V_ID is equal between the two list and the value can be null or equal to the value of the parent's list. 我需要在两个列表之间进行比较,并根据条件从子列表中找出可以完全选择还是拒绝的子列表: 如果两个列表之间的V_ID相等,并且该值可以为null或等于父列表的值。

I will not be able to convert the list to Dictionary as I will not be identify the item uniquely without the primary ID of the entity. 我将无法将列表转换为字典,因为如果没有实体的主要ID,我将无法唯一标识该项目。 Let me know if there is a way to do it via dictionary. 让我知道是否可以通过字典进行操作。

Please help me how can I achieve this and I have tried various ways including LINQ, for-each, etc as all the entities in the child list are either completely rejected or selected. 请帮助我如何实现这一目标,并且我尝试了多种方式,包括LINQ,for-each等,因为子级列表中的所有实体都被完全拒绝或选中。

Also am new to C# and Linq and I have provide the code sample which is extracted out from my original source code and various scenarios examples. 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
}

Data Sample: 数据样本:

Parent List 父母名单

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

Child List A: 子清单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

Child List B 子清单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

Child List C 子清单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.

The first thing I would do for the sake of simplicity is make the comparison its own function. 为了简单起见,我要做的第一件事就是使比较成为其自己的功能。 This isn't critical, but it will help with readability. 这不是关键,但有助于提高可读性。 I don't know what the condition describes, so I'll just call it TheCondition . 我不知道条件描述了什么,所以我将其TheCondition (Also, if there's a bug in the condition itself it may be easier to spot this way.) (此外,如果条件本身存在错误,则更容易发现这种情况。)

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

Then, to get the elements you want from the child list 然后,从子列表中获取所需的元素

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

Specifying == true just to make it easier to read. 指定== true只是为了使其更易于阅读。 In "real life" I would just use 在“现实生活”中,我只会使用

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

since that function already returns a boolean. 因为该函数已经返回了布尔值。

Now selected is an IEnumerable<MyEntity> . 现在selectedIEnumerable<MyEntity> To get a list of ids, 要获取ID列表,

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

What we're saying is 'select from the child list where the condition is true for that child and any parent from the parent list.' 我们要说的是“从子列表中选择条件,该条件适用于该孩子以及父列表中的任何父项。” Using Any means that if it does find a match with one of the parents it doesn't need to do a comparison with all of the other parents. 使用Any意味着如果它确实找到了与其中一个父母的匹配,则不需要与所有其他父母进行比较。

Then in the last step we're saying 'select all of the IDs from the previous list of entities' which returns an IEnumerable<int> and then create a new List<int> from those values. 然后,在最后一步中,我们说“从先前的实体列表中选择所有ID”,这将返回IEnumerable<int> ,然后根据这些值创建一个新的List<int>


This could even be a little bit clearer if we break it up some more. 如果我们再分解一些,这甚至可能更清楚一点。 I wouldn't necessarily do this every time, but it can make it easier to follow. 我不一定每次都这样做,但是它可以使您更容易理解。 (I struggled with this at first - maybe you'll catch on faster than I did.) (起初我为此感到苦恼-也许您会比我快得多。)

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

You could also chain these together list this, combining them into one statement. 您也可以将这些链接在一起,将其列出,然后将它们组合成一个语句。

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

For me I needed to understand how it worked separately, and then it's easier to start combining them together. 对我来说,我需要了解它是如何单独工作的,然后将它们组合在一起会更容易。 But sometimes for the sake of readability it's still good to separate them out. 但是有时出于可读性考虑,将它们分开仍然是很好的。

One way this can be accomplished is with a LINQ query language statement. 一种可以实现此目的的方法是使用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();                           

Note the boolean NOT ( ! ). 请注意,布尔值NOT( ! )。 If there are any results left after filtering, the child should be rejected. 如果过滤后还有任何结果,则应拒绝该孩子。

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

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