2

我有一堂课如下:

Object1{
   int id;
   DateTime time;
}

我有一个清单Object1。如果时间值晚于列表中的时间值,我想循环浏览另一个列表Object1,搜索具有相同 ID 的 并在第一个列表中替换它。Object1如果该项目不在第一个列表中,则添加它。

我确信有一种优雅的方法可以做到这一点,也许使用 linq?:

List<Object1> listOfNewestItems = new List<Object1>();
List<Object1> listToCycleThrough = MethodToReturnList();
foreach(Object1 object in listToCycleThrough){
   if(listOfNewestItems.Contains(//object1 with same id as object))
   {
      //check date, replace if time property is > existing time property 
   } else {
      listOfNewestItems.Add(object)
}

显然这是非常混乱的(甚至没有检查更混乱的属性......),有没有更清洁的方法来做到这一点?

4

4 回答 4

7
var finalList = list1.Concat(list2)
                     .GroupBy(x => x.id)
                     .Select(x => x.OrderByDescending(y=>y.time).First())
                     .ToList();

这是要测试的完整代码

public class Object1
{
    public int id;
    public DateTime time;
}

List<Object1> list1 = new List<Object1>() 
{
    new Object1(){id=1,time=new DateTime(1991,1,1)},
    new Object1(){id=2,time=new DateTime(1992,1,1)}
};

List<Object1> list2 = new List<Object1>() 
{
    new Object1(){id=1,time=new DateTime(2001,1,1)},
    new Object1(){id=3,time=new DateTime(1993,1,1)}
};

和输出:

1 01.01.2001 
2 01.01.1992 
3 01.01.1993 
于 2012-09-28T11:58:14.213 回答
1

这是如何检查:

foreach(var object in listToCycleThrough)
{
    var currentObject = listOfNewestItems
                              .SingleOrDefault(obj => obj.Id == object.Id);

    if(currentObject != null)
    {
        if (currentObject.Time < object.Time) 
                  currentObject.Time = object.Time
    } 

    else 
        listOfNewestItems.Add(object)
}

但是如果你有大数据,建议Dictionary在最新列表中使用,查找时间将是 O(1) 而不是 O(n)

于 2012-09-28T10:43:16.637 回答
0

您可以使用 LINQ。Enumerable.Except获得设定的差异(最新的),并join找到较新的对象。

var listOfNewestIDs = listOfNewestItems.Select(o => o.id);
var listToCycleIDs = listToCycleThrough.Select(o => o.id);
var newestIDs = listOfNewestIDs.Except(listToCycleIDs);
var newestObjects = from obj in listOfNewestItems
                    join objID in newestIDs on obj.id equals objID
                    select obj;
var updateObjects = from newObj in listOfNewestItems
                    join oldObj in listToCycleThrough on newObj.id equals oldObj.id
                    where newObj.time > oldObj.time
                    select new { oldObj, newObj };

foreach (var updObject in updateObjects)
    updObject.oldObj.time = updObject.newObj.time;
listToCycleThrough.AddRange(newestObjects);

请注意,您需要添加using System.Linq;.

这是一个演示:http: //ideone.com/2ASli

于 2012-09-28T10:43:29.437 回答
0

我会创建一个Dictionary来查找索引Id并使用它

var newItems = new List<Object1> { ...
IList<Object1> itemsToUpdate = ... 

var lookup = itemsToUpdate.
        Select((i, o) => new { Key = o.id, Value = i }).
        ToDictionary(i => i.Key, i => i.Value);

foreach (var newItem in newitems)
{
    if (lookup.ContainsKey(newitem.ID))
    {
        var i = lookup[newItem.Id];
        if (newItem.time > itemsToUpdate[i].time)
        {
            itemsToUpdate[i] = newItem;
        }
    }
    else
    {
        itemsToUpdate.Add(newItem)
    }
}

这样,您就不需要为每个新项目重新枚举列表,您将受益于哈希查找性能。


这应该可以Id在新项目列表中重复多次。

于 2012-09-28T11:17:56.917 回答