是否有更简洁的方式来表达这个foreach循环?

时间:2012-11-20 12:43:22

标签: c# linq

我需要合并2个列表。列表1只有日期,列表2也可以有时间元素:

var List1 = new[] { 
  new ListType{ val = new DateTime(2012, 1, 1)}, 
  new ListType{ val = new DateTime(2012, 1, 2)} 
};

List2 = new[] { new ListType{ val = new DateTime(2012, 1, 1, 5, 0, 0)} };

FinalList = new[] { 
  new ListType{ val = new DateTime(2012, 1, 1, 5, 0, 0)}, 
  new ListType{ val = new DateTime(2012, 1, 2)} 
};

我的方式是:

foreach (var l in List1) {
  var match = List2.FirstOrDefault(q => q.val.Date == l.val);
  if (match == null) continue;
  l.val = match.val;
}

有没有比使用FirstOrDefault迭代List1更好的方法,然后重新分配val?它有效,所以如果Linq有一种更优雅的方式(即我错过了一些明显的东西),这更是一种好奇心。

由于

2 个答案:

答案 0 :(得分:0)

您可以将Enumerable.Union与自定义IEqualityComparer<ListType>

一起使用
class ListType
{
    public DateTime val { get; set; }

    public class DateComparer : IEqualityComparer<ListType>
    {
        public bool Equals(ListType x, ListType y)
        {
            if (ReferenceEquals(x, y))
                return true;
            else if (x == null || y == null)
                return false;
            return x.val.Date == y.val.Date;
        }

        public int GetHashCode(ListType obj)
        {
            return obj.val.Date.GetHashCode();
        }
    }
}

然后......

var finalList = List2.Union(List1, new ListType.DateComparer());

答案 1 :(得分:0)

我不会摆脱循环,但为了提高效率,我会建立一个字典映射日期到第一个matchnig时间:

var dateToTime = List2
    .GroupBy(d => d.Date)
    .ToDictionary(g => g.Key, g => g.First());
foreach (var l in List1)
{
    DateTime match;
    if (dateToTime.TryGetValue(l.val, out match))
        l.val = match.val;
}

LINQ用于查询项目而不是更新项目 - 如果需要更新项目,请使用非LINQ,如foreach循环。也就是说,如果您想从第一个列表中的项目生成 new 列表,则以下内容等同于您的代码:

var newList = List1.Select(l => new ListType { val = 
    dateToTime.ContainsKey(l.val) ? dateToTime[l.val] : l.val }).ToList();