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

时间:2009-06-05 13:48:09

标签: 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

我想在List2中插入行,以便List1中的每个人在List2中至少有一行。因此,当List2中没有针对某个人的行时,我想插入一个具有默认值的行。在示例中,我将不得不为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

有没有人有一个聪明,干净,有效的方法呢?

我知道要将这些表合并为一个,我必须使用外部联接,例如在此Outer Join Sample中。但我不想要一个新的结果集。我只想将那些缺失的行插入到List2中。

注意: 是的,我知道问题\标题有点......等等......但我不知道如何制定它更好。如果可以,请有人修理。

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

10 个答案:

答案 0 :(得分:1)

假设您的列表按照示例中的 Key 值排序(在本例中为整数),这样的事情应该有效:

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

根据您希望丢失的项目数量,您可能希望将插入替换为List2,从而无需求助。但是,如果您希望丢失大量项目,则此方法会更快。或者,您可以使用List2的链接列表。

请注意,如果List1中存在重复的键条目,则会失败。您需要单独检查它以防止在List2中创建多个新项目。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

LINQ:从您在链接中提供的示例中,只需更改代码:

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

foreach (var i in q) {
    if (i.OrderNumber == "(no orders)")
        order.Add(new Order {Key = i.ID /* add your default values here*/});
}

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

答案 3 :(得分:0)

好的,这是: 1.创建一个类型来表示列表中的项目:

 struct ListType
        {
            public object Id;
            public object Name;
        }

或者,当然你可以用另一种更适合你的方式建造。

  1. 将List2创建为IEnumerable&lt; ListType&gt;来自您的LINQ查询

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

  3. 根据上述假设,这里是解决初始问题的代码:

    列出newLst2 = list2.ToList();

    Array.ForEach(list1.ToArray(), list1It =>
    {
       var isInList2 = from list2it in newLst2.ToArray()
                       where (string)list2it.Id == list1It.Id
                       select list2it;
    
       if (isInList2.Count() == 0)
           newLst2.Add(new ListType { Id = list1It.Id, Name = list1It.Name });
    
    });     
    
  4. 注释:对于List1中的每个元素,在List2中进行查询并检查Id是否存在。如果它不存在,请添加新项目。

    可能有更有效的方法,但这应该可以让你开始。

答案 4 :(得分:0)

这是使用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));

答案 5 :(得分:0)

呃......好像只使用Contains,不是吗?

foreach (Key key in List1.Keys)
{
   if (!List2.Keys.Contains(key)) List2.Add(key, "0");
}

这对List1中的重复键没有任何问题。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

你可能不喜欢我的解决方案。但我要感谢你的这篇文章。 它让我有机会使用linq做一些有用的东西。

我正在使用Extension方法和Linq在目标列表中添加缺少的项目(List2)。 我不确定你是否正在使用3.0 / 3.5框架,如果你这样做,那么这个解决方案对你有用,它也是“一种聪明,干净,有效的方式”:)。

 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;
        }
      }

答案 8 :(得分:-1)

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

答案 9 :(得分:-2)

在数据库上使用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表中的其他列是NOT NULL或具有DEFAULT值约束。