C#:创建其他列表中不存在的对象

C#:创建其他列表中不存在的对象,c#,linq,list,C#,Linq,List,我有两个列表,其中包含两种不同类型的对象,表示来自两个sql查询的数据行。第一个列表包含数据,第二个列表包含更详细的数据。例如: List1: List2: 1 Alice 1 15 2 Bob 1 19 3 Carol 2 5 4 Dave 2 7 2 20 4 16 我想在列表2中插入行,以便列表1中的每个人在列表2中至少有一行

我有两个列表,其中包含两种不同类型的对象,表示来自两个sql查询的数据行。第一个列表包含数据,第二个列表包含更详细的数据。例如:

List1:        List2:
 1   Alice     1   15
 2   Bob       1   19
 3   Carol     2    5
 4   Dave      2    7
               2   20
               4   16
我想在列表2中插入行,以便列表1中的每个人在列表2中至少有一行。因此,当某个人的列表2中不存在行时,我想插入一个带有默认值的行。在本例中,我必须为Carol插入一行,因此我将以以下内容结束:

List1:        List2:
 1   Alice     1   15
 2   Bob       1   19
 3   Carol     2    5
 4   Dave      2    7
               2   20
               3    0
               4   16
有人有聪明、干净、高效的方法吗

我知道要将这些表连接到一个表中,我必须使用外部连接,例如这样的连接。但我不想要新的结果集。我只想将那些缺少的行插入到列表2中

注意:是的,我知道这个问题\标题有点。。。废话。。。但我不知道如何更好地表述它。如果可以的话,请找个人修理一下


注2:我不能使用SQL。我无法在原始表中插入这些行。我在报告数据,这意味着我不接触任何数据。我只是念出来。数据将用于主详细信息报告,我的问题是,当某个主行不存在详细信息时,您最终只会得到一个空白。这不好。因此,我想插入带有合理信息的行,以便用户可以看到此处没有显示任何内容。

使用数据库上的SQL,解决方案是:

INSERT INTO List2 (ID)
SELECT      l1.ID
FROM        List1 l1
LEFT JOIN   List2 l2
        ON  l1.ID = l2.ID
WHERE       l2.ID IS NULL

这里假设List2表中的其他列不是空的,或者具有默认值约束。

假设您的列表是按键值排序的,如示例中所示(在本例中为整数),类似这样的操作应该有效:

INSERT INTO List2(ID, Value)
SELECT      ID, 0
FROM        List1
WHERE       NOT EXISTS (SELECT NULL FROM List2 WHERE List2.ID=List1.ID)
int i = 0;

foreach (var item in List1)
{
    // Skip any items in List2 that don't exist in List1
    // (not sure this is needed in your case), or that we've
    // already passed in List1
    while (List2[i].Key < item.Key)
        i++;

    if (List2[i].Key > item.Key)
    {
        // Create new item in List2
        List2.Add(new List2Item(item.Key, 0));
    }
}

// TODO: resort List2
inti=0;
foreach(列表1中的变量项)
{
//跳过列表2中列表1中不存在的任何项目
//(不确定您的情况是否需要),或者我们已经
//已通过列表1
while(List2[i].Keyitem.Key)
{
//在列表2中创建新项
List2.Add(新的List2Item(item.Key,0));
}
}
//TODO:度假酒店列表2
根据您希望丢失的项目的数量,您可能希望将其插入到列表2中,这样就不需要重新调用。但是,如果您希望丢失很多项,则此方法会更快。或者,您可以使用列表2的链接列表


请注意,如果列表1中存在重复的键条目,则此操作将失败。您需要单独检查,以防止在列表2中创建多个新项目。

LINQ:根据您在链接中给出的示例,只需将代码更改为:

foreach (var i in q) {
    Console.WriteLine("Customer: {0}  Order Number: {1}", 
        i.Name.PadRight(11, ' '), i.OrderNumber);
}

当然,您也可以在此之前的代码中保存一些行。

好的,下面是: 1.创建一个类型以表示列表中的项目:

 struct ListType
        {
            public object Id;
            public object Name;
        }
当然,你也可以用另一种更适合你的方式来构建

  • 从LINQ查询中将List2创建为IEnumerable

  • 我假设List1与List2具有相同的结构,具有Id和Name字段(可以对列表项使用相同的ListType类型)

  • 根据上述假设,以下是解决初始问题的代码:

    List newLst2=list2.ToList()

  • 注释:对于列表1中的每个元素,在列表2中进行查询并检查Id是否存在。如果不存在,请添加新项目


    也许有更有效的方法可以做到这一点,但这应该能够让您开始。

    这里有一个使用LINQ的解决方案

    public class List1
    {
        public int ID { get; set; }
        public string Person { get; set; }
    }
    
    public class List2
    {
        public int ID { get; set; }
        public int Value { get; set; }
    }
    
    var lList1 = new List<List1>
                 {
                    new List1 {ID = 1, Person = "Alice"},
                    new List1 {ID = 2, Person = "Bob"},
                    new List1 {ID = 3, Person = "Carol"},
                    new List1 {ID = 4, Person = "Dave"}
                 };
    
    
    var lList2 = new List<List2>
                 {
                   new List2 {ID = 1, Value = 15},
                   new List2 {ID = 1, Value = 19},
                   new List2 {ID = 2, Value = 5},
                   new List2 {ID = 2, Value = 7},
                   new List2 {ID = 2, Value = 20},
                   new List2 {ID = 4, Value = 16}
                 };
    
    var lOutput = lList1.SelectMany(pArg => 
                                 lList2.Where(pArg1 => pArg1.ID == pArg.ID)
                                       .DefaultIfEmpty(new List2 { ID = pArg.ID, Value = 0})
                                       .Select(pArg1 => pArg1));
    
    公共类列表1
    {
    公共int ID{get;set;}
    公共字符串Person{get;set;}
    }
    公共类列表2
    {
    公共int ID{get;set;}
    公共int值{get;set;}
    }
    var lList1=新列表
    {
    新列表1{ID=1,Person=“Alice”},
    新列表1{ID=2,Person=“Bob”},
    新列表1{ID=3,Person=“Carol”},
    新列表1{ID=4,Person=“Dave”}
    };
    var lList2=新列表
    {
    新列表2{ID=1,Value=15},
    新列表2{ID=1,Value=19},
    新列表2{ID=2,Value=5},
    新列表2{ID=2,Value=7},
    新列表2{ID=2,Value=20},
    新列表2{ID=4,Value=16}
    };
    var lOutput=lList1。SelectMany(参数=>
    其中(pArg1=>pArg1.ID==pArg.ID)
    .DefaultIfEmpty(新列表2{ID=pArg.ID,Value=0})
    .选择(pArg1=>pArg1));
    
    嗯。。。似乎只要使用Contains就可以了,不是吗

    foreach (Key key in List1.Keys)
    {
       if (!List2.Keys.Contains(key)) List2.Add(key, "0");
    }
    
    对于列表1中的重复键,这不会有任何问题。

    LINQ实现

    public class Master
    {
        public int ID;
    }
    
    public class Detail
    {
        public int ID;
        public int Count;
    }
    
    public static void AddMissingDetails(IEnumerable<Master> masters, List<Detail> details)
    {
        AddMissingDetails(masters, details, x => new Detail
            {
                ID = x,
                Count = 0
            });
    }
    
    public static void AddMissingDetails(IEnumerable<Master> masters, List<Detail> details, Func<int, Detail> createDefault)
    {
        details.AddRange(
            masters
                .Select(x => x.ID)
                .Except(details.Select(x => x.ID).Distinct())
                .Select(createDefault));
    }
    
    公共类主控
    {
    公共int ID;
    }
    公共类详细信息
    {
    公共int ID;
    公共整数计数;
    }
    公共静态void AddMissingDetails(IEnumerable masters,列表详细信息)
    {
    AddMissingDetails(主控、详细信息,x=>新详细信息
    {
    ID=x,
    计数=0
    });
    }
    公共静态void AddMissingDetails(IEnumerable masters、列表详细信息、Func createDefault)
    {
    details.AddRange(
    大师
    .选择(x=>x.ID)
    .Except(details.Select(x=>x.ID).Distinct())
    .选择(createDefault));
    }
    
    您可能不喜欢我的解决方案。但我要感谢你的这篇文章。 这让我有机会使用linq做一些有用的事情

    我使用扩展方法和Linq在目标列表(列表2)中添加缺少的项。 我不确定您是否正在使用3.0/3.5框架,如果您正在使用,那么此解决方案将适合您,并且它也是“一种聪明、干净和高效的方法”:

    publicstaticvoidmergelists(){
    var listOne=新列表{
    新列表1{ID=1,Person=“Alice”},
    新列表1{ID=2,Person=“Bob”},
    新列表1{ID=3,Person=“Carol”
    
    foreach (Key key in List1.Keys)
    {
       if (!List2.Keys.Contains(key)) List2.Add(key, "0");
    }
    
    public class Master
    {
        public int ID;
    }
    
    public class Detail
    {
        public int ID;
        public int Count;
    }
    
    public static void AddMissingDetails(IEnumerable<Master> masters, List<Detail> details)
    {
        AddMissingDetails(masters, details, x => new Detail
            {
                ID = x,
                Count = 0
            });
    }
    
    public static void AddMissingDetails(IEnumerable<Master> masters, List<Detail> details, Func<int, Detail> createDefault)
    {
        details.AddRange(
            masters
                .Select(x => x.ID)
                .Except(details.Select(x => x.ID).Distinct())
                .Select(createDefault));
    }
    
     public static void MergeLists() {
          var listOne=new List<List1> {
            new List1 {ID=1, Person="Alice"},
            new List1 {ID=2, Person="Bob"},
            new List1 {ID=3, Person="Carol"},
            new List1 {ID=4, Person="Dave"},
            new List1 {ID=5, Person="Dave2"},
            new List1 {ID=6, Person="Dave3"},
          };
          var listTwo=new List<List2> {
            new List2 {ID=1, Value=15},
            new List2 {ID=1, Value=19},
            new List2 {ID=2, Value=5},
            new List2 {ID=2, Value=7},
            new List2 {ID=2, Value=20},
            new List2 {ID=4, Value=16}
          };
    
          var listTwoWithAddedItems=listOne.AddMissingItems(listTwo, (item1, item2) => item1.ID==item2.ID,
                                                        item2 => new List2 { ID=item2.ID, Value=-1 }).ToList();//For this value, you can put whatever default value you want to set for the missing items.
    
          Console.Read();
        }
    
         public static class AmbyExtends {
    
            public static List<Target> AddMissingItems<Source, Target>(this IEnumerable<Source> source, List<Target> target, Func<Source, Target, bool> selector, Func<Source, Target> creator) {
              foreach(var item in source) {
                if(!target.Any(x=>selector(item,x))) {
                  target.Add(creator(item));
                }         
              }
              return target;
            }
          }
    
    var lst1 = new List<int>() { 1, 2, 3, 4 };
    var lst2 = new List<int>() { 1, 1, 2, 2, 2, 4 };
    
    lst2.AddRange(lst1.Except(lst2));