将集合与对象进行比较并复制差异

时间:2015-03-16 07:47:19

标签: c# linq collections

我有一个收藏品:

Collection<DateOfValues> collectionDateOfValues;
...

我得到一个DateOfValues实例 - 让我们说dateOfValuesNew并想要迭代集合并仅覆盖不同的值。

public class DateOfValues
{
   {
      this.Values = new Collection<SomeValue>();
   }

   public int id { get; set;}    
   public DateTime Start { get; set; }    
   public Collection<SomeValue> Values;
}

public class SomeValue
{
   public int Id { get; set; }
   public DateOfValues Date { get; set; }
   public string Status { get; set; }
   publi decimal StatusNumber { get; set; }
}

我做了什么:

if (dateOfValuesNew != null)
{
   foreach (var dateOfValues in collectionDateOfValues)
   {
      if (dateOfValues.Id == dateOfValuesNew.Id)
      {
         // Here Im sure to find the dateOfValues Instance I will work with.
      }
   }
}

但是,如果我想将dateOfValuesdateOfValuesNewforeach进行比较,那就很难看了。

有没有更好的方法呢?

可以更改DateOfValues的Start。这是最简单的部分 - 因为我可以简单地覆盖它。

困难的部分是比较SomeValue Collection。每个SomeValue都可以更改DateStatus - 这也可以通过覆盖来解决。

但SomeValue Collection可以成为新的SomeValue,也可以删除。

例如,dateOfValues在SomeValue Collection中有3个SomeValue,而dateOfValuesNew将有4个或2个。

1 个答案:

答案 0 :(得分:1)

有点棘手,但这有效:

class Program
{
    static void Main(string[] args)
    {
        // Test
        DateOfValues dov1 = new DateOfValues { Id = 1, Start = new DateTime(2011, 12, 01) };
        dov1.AddSomeValue(1,"OK",2);
        dov1.AddSomeValue(2,"Not OK",3);
        dov1.AddSomeValue(3,"Not OK",4);
        dov1.AddSomeValue(4,"Additional dov1",5);


        DateOfValues dov2 = new DateOfValues { Id = 1, Start = new DateTime(2011, 12, 02) };
        dov2.AddSomeValue(1, "OK", 2);
        dov2.AddSomeValue(2, "Not OK", 4);
        dov2.AddSomeValue(3, "OK", 1);
        dov2.AddSomeValue(6, "Additional dov2", 15);

        foreach (Tuple<SomeValue,SomeValue> difference in dov1.GetDifference(dov2))
        {
            if (difference.Item1 != null)
            {
                Console.WriteLine("Item1: Id:{0}; Status:{1}; Status Number:{2}",
                    difference.Item1.Id, difference.Item1.Status, difference.Item1.StatusNumber);
            }
            if (difference.Item2 != null)
            {
                Console.WriteLine("Item2: Id:{0}; Status:{1}; Status Number:{2}",
                    difference.Item2.Id, difference.Item2.Status, difference.Item2.StatusNumber);
            }
            Console.WriteLine("-------------------------------------------");
        }

    }
}

public class DateOfValues
{
    public DateOfValues()
    {
        Values = new Collection<SomeValue>();
    }

    public int Id { get; set; }
    public DateTime Start { get; set; }
    public Collection<SomeValue> Values;

    public void AddSomeValue(int id, string status, decimal statusNumber)
    {
        Values.Add(new SomeValue{Date = this,Id = id,Status = status,StatusNumber = statusNumber});
    }

    public IEnumerable<Tuple<SomeValue, SomeValue>> GetDifference(DateOfValues other)
    {
        IEnumerable<SomeValue> notMatching = Values.Where(v => !other.Values.Any(o => v.Equals(o)))
            .Union(other.Values.Where(v=> !Values.Any(o=> v.Equals(o)))).Distinct();

        return notMatching
            .GroupBy(x => x.Id)
            .Select(x => 
                new Tuple<SomeValue, SomeValue>(
                    x.FirstOrDefault(y => y.Date == this), x.FirstOrDefault(y => y.Date == other)));
    }

}

public class SomeValue : IEquatable<SomeValue>
{
    public int Id { get; set; }
    public DateOfValues Date { get; set; }
    public string Status { get; set; }
    public decimal StatusNumber { get; set; }

    public bool Equals(SomeValue other)
    {
        return other.Id == Id && other.Status == Status && other.StatusNumber == StatusNumber;
    }
}

输出:

Item1: Id:2; Status:Not OK; Status Number:3 
Item2: Id:2; Status:Not OK; Status Number:4
-------------------------------------------
Item1: Id:3; Status:Not OK; Status Number:4 
Item2: Id:3; Status:OK; Status Number:1
-------------------------------------------
Item1: Id:4; Status:Additional dov1; Status Number:5
------------------------------------------- 
Item2: Id:6; Status:Additional dov2; Status Number:15
-------------------------------------------

修改

替代方案,您可以使用EqualityComparer:

public class DateOfValues
{
    public DateOfValues()
    {
        Values = new Collection<SomeValue>();
    }

    public int Id { get; set; }
    public DateTime Start { get; set; }
    public Collection<SomeValue> Values;

    public void AddSomeValue(int id, string status, decimal statusNumber)
    {
        Values.Add(new SomeValue { Date = this, Id = id, Status = status, StatusNumber = statusNumber });
    }

    public IEnumerable<Tuple<SomeValue, SomeValue>> GetDifference(DateOfValues other)
    {
        var notMatching = Values.Except(other.Values, new SomeValueComparer())
            .Union(other.Values.Except(Values,new SomeValueComparer()));

        return notMatching
            .GroupBy(x => x.Id)
            .Select(x =>
                new Tuple<SomeValue, SomeValue>(
                    x.FirstOrDefault(y => y.Date == this), x.FirstOrDefault(y => y.Date == other)));
    }

}

public class SomeValueComparer : IEqualityComparer<SomeValue>
{
    public bool Equals(SomeValue x, SomeValue y)
    {
        return 
            x.Id == y.Id &&
            x.Status == y.Status &&
            x.StatusNumber == y.StatusNumber;
    }

    public int GetHashCode(SomeValue obj)
    {
        return obj.GetHashCode();
    }
}


public class SomeValue
{
    public int Id { get; set; }
    public DateOfValues Date { get; set; }
    public string Status { get; set; }
    public decimal StatusNumber { get; set; }

    public override int GetHashCode()
    {
        return string.Format("{0}{1}{2}",Id,Status,StatusNumber).GetHashCode();
        // or a better method to get a hashcode
    }
}