Это двустороннее сравнение списков, которое вы можете получить с помощью Linq IEnumerable.Except()
и IEnumerable.Intersect()
.
Первое, что вы должны сделать, это написать класс для хранения элементов данных. :
sealed class Data
{
public string Serial { get; }
public int Amount { get; }
public Data(string serial, int amount)
{
Serial = serial;
Amount = amount;
}
}
Следующее, что вам нужно сделать, это написать IEqualityComparer<T>
, который вы можете использовать для сравнения предметов (вам понадобится это для использования Intersect()
и Except()
:
sealed class DataComparer : IEqualityComparer<Data>
{
public bool Equals(Data x, Data y)
{
return x.Serial.Equals(y.Serial);
}
public int GetHashCode(Data obj)
{
return obj.Serial.GetHashCode();
}
}
Теперь напишите класс для получения данных сравнения:
enum ComparisonState
{
Unchanged,
Changed,
New,
Deleted
}
sealed class ComparedData
{
public Data Data { get; }
public int PreviousAmount { get; }
public ComparisonState ComparisonState { get; }
public ComparedData(Data data, ComparisonState comparisonState, int previousAmount)
{
Data = data;
ComparisonState = comparisonState;
PreviousAmount = previousAmount;
}
public override string ToString()
{
if (ComparisonState == ComparisonState.Changed)
return $"Serial: {Data.Serial}, Amount: {PreviousAmount}, New amount: {Data.Amount}, Status: Changed";
else
return $"Serial: {Data.Serial}, Amount: {Data.Amount}, Status: {ComparisonState}";
}
}
(я добавил ToString()
к этому классу для удобства.)
Теперь вы можетеиспользуйте Linq следующим образом. Прочитайте комментарии, чтобы увидеть, как это работает:
class Program
{
public static void Main()
{
var list1 = new List<Data>
{
new Data("63245-8", 10),
new Data("08657-5", 100),
new Data("29995-0", 500),
new Data("12345-0", 42)
};
var list2 = new List<Data>
{
new Data("63245-8", 100),
new Data("12345-0", 42),
new Data("67455-1", 100),
new Data("44187-10", 50),
};
var comparer = new DataComparer();
var newItems = list2.Except(list1, comparer); // The second list without items from the first list = new items.
var deletedItems = list1.Except(list2, comparer); // The first list without items from the second list = deleted items.
var keptItems = list2.Intersect(list1, comparer); // Items in both lists = kept items (but note: Amount may have changed).
List<ComparedData> result = new List<ComparedData>();
result.AddRange(newItems .Select(item => new ComparedData(item, ComparisonState.New, 0)));
result.AddRange(deletedItems.Select(item => new ComparedData(item, ComparisonState.Deleted, 0)));
// For each item in the kept list, determine if it changed by comparing it to the first list.
// Note that the "list1.Find()` is an O(N) operation making this quite slow.
// You could speed it up for large collections by putting list1 into a dictionary and looking items up in it -
// but this is unlikely to be needed for smaller collections.
result.AddRange(keptItems.Select(item =>
{
var previous = list1.Find(other => other.Serial == item.Serial);
return new ComparedData(item, item.Amount == previous.Amount ? ComparisonState.Unchanged : ComparisonState.Changed, previous.Amount);
}));
// Print the result, for illustration.
foreach (var item in result)
Console.WriteLine(item);
}
}
Вывод этого выглядит следующим образом:
Serial: 67455-1, Amount: 100, Status: New
Serial: 44187-10, Amount: 50, Status: New
Serial: 08657-5, Amount: 100, Status: Deleted
Serial: 29995-0, Amount: 500, Status: Deleted
Serial: 63245-8, Amount: 10, New amount: 100, Status: Changed
Serial: 12345-0, Amount: 42, Status: Unchanged
Скрипка DotNet здесь