2

私は次のようなクラスを持っています:

Object1{
   int id;
   DateTime time;
}

のリストがありObject1ます。の別のリストを循環させ、同じ ID の をObject1検索し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(n) ではなく O(1) になります。

于 2012-09-28T10:43:16.637 に答える
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 に答える
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 に答える