【问题标题】:Compare collection with objects and copy the differences将集合与对象进行比较并复制差异
【发布时间】:2015-03-16 07:47:19
【问题描述】:

我有一个收藏:

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 集合中有 3 个 SomeValue 而 dateOfValuesNew 将有 4 或 2。

【问题讨论】:

  • 为什么不使用Except ??
  • @CoderofCode Except 与对象集合?用我的代码向我展示示例。对于dateOfValuesNew 将具有相同数量的Values 的情况,假设为3。而SomeValue 数字2 将具有不同的StatusNumber
  • 这个问题对我来说似乎不是很清楚。我很难理解SomeValue 如何适应所有这些,以及问题所在。正如您所说(我认为),您始终可以无条件地覆盖这些值;如果它们不同,您就实现了目标,如果没有,那么您只是用相同的值覆盖,所以不会造成伤害。请提供a good, minimal, complete code example 并清楚地解释该示例的作用,以及它与您希望它做什么的不同之处。
  • @PeterDuniho 确定我已尝试显示最少的代码。还有我所做的事情和我的想法。有时我无法让它更容易理解。
  • @PeterDuniho 如果您看到可以简化的内容或使问题更具可读性 - 您可以帮助编辑。

标签: c# linq collections


【解决方案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
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2011-06-24
    相关资源
    最近更新 更多