Какой шаблон / алгоритм наиболее эффективен для сравнения двух списков и нахождения дельты между этими двумя списками? - PullRequest
12 голосов
/ 10 сентября 2010

У нас есть два списка, скажем, студентов и их оценки. Я хочу сравнить эти два списка и найти разницу между новым списком и старым списком, а затем найти наименее навязчивый способ вставить или обновить в новый список любые изменения. Какой алгоритм лучше всего подходит для этого? Хотите сосредоточиться на минимальном количестве изменений в новом списке и производительности.

Пример кода:

List<ListItem> existingList = new List<ListItem>();
List<ListItem> newList = new List<ListItem>();

public TopLists()
{
  InitTwoLists();
}

private void InitTwoLists()
{
  existingList.Add(new ListItem { Name = "Shane", Score = 100 });
  existingList.Add(new ListItem { Name = "Mark", Score = 95 });
  existingList.Add(new ListItem { Name = "Shane", Score = 94 });
  existingList.Add(new ListItem { Name = "Steve", Score = 90 });
  existingList.Add(new ListItem { Name = "Brian", Score = 85 });
  existingList.Add(new ListItem { Name = "Craig", Score = 85 });
  existingList.Add(new ListItem { Name = "John", Score = 82 });
  existingList.Add(new ListItem { Name = "Steve", Score = 81 });
  existingList.Add(new ListItem { Name = "Philip", Score = 79 });
  existingList.Add(new ListItem { Name = "Peter", Score = 70 });

  newList.Add(new ListItem { Name = "Shane", Score = 100 });
  newList.Add(new ListItem { Name = "Steve", Score = 96 });  // This is change
  newList.Add(new ListItem { Name = "Mark", Score = 95 });
  newList.Add(new ListItem { Name = "Shane", Score = 94 });
  newList.Add(new ListItem { Name = "Brian", Score = 85 });
  newList.Add(new ListItem { Name = "Craig", Score = 85 });
  newList.Add(new ListItem { Name = "John", Score = 82 });
  newList.Add(new ListItem { Name = "Steve", Score = 81 });
  newList.Add(new ListItem { Name = "Philip", Score = 79 });
  newList.Add(new ListItem { Name = "Peter", Score = 70 });
}
}

public void CompareLists()
{
  // How would I find the deltas and update the new list with any changes from old?
}
}

public class ListItem
{
  public string Name { get; set; }
  public int Score { get; set; }
}

** РЕДАКТИРОВАТЬ: Желаемый выход ***

Желаемый вывод - фактически изменить новый список с помощью дельт. Например, в этом сценарии:

newList.Add(new ListItem { Name = "Shane", Score = 100 });
  newList.Add(new ListItem { Name = "Steve", Score = 96 });  // This is change
  newList.Add(new ListItem { Name = "Mark", Score = 95 });
  newList.Add(new ListItem { Name = "Shane", Score = 94 });
  newList.Add(new ListItem { Name = "Brian", Score = 85 });
  newList.Add(new ListItem { Name = "Craig", Score = 85 });
  newList.Add(new ListItem { Name = "John", Score = 82 });
  newList.Add(new ListItem { Name = "Steve", Score = 81 });
  newList.Add(new ListItem { Name = "Roger", Score = 80 });  // Roger is a new entry
  newList.Add(new ListItem { Name = "Phillip", Score = 79 });  // Philip moved down one

// Питер выпадает из этого списка со своим счетом 70, так как я хочу только топ-10.

Таким образом, изменения будут:

Обновление записи 2 для "Стива", счет изменился Вставьте новую запись "Роджер" в позиции 9 Сбросить рекорд для "Питера" с топ-10.

Ответы [ 3 ]

4 голосов
/ 10 сентября 2010

Можете ли вы использовать Linq:

List<ListItem> list1 = GetYourList1();
List<ListItem> list2 = GetYourList2();
var diff = list1.Except(list2);

Ваш конкретный пример:

var diff = newList.Except(existingList);

Не уверен, что он самый эффективный, но он лаконичный:)

3 голосов
/ 11 сентября 2010

Это можно сделать, если у вас нет одного и того же имени дважды в вашем списке.В вашем примере у вас есть 2x Стив, но вам нужен способ различать их.

public static List<ListItem> CompareLists(List<ListItem> existingList, List<ListItem> newList)
{
    List<ListItem> mergedList = new List<ListItem>();
    mergedList.AddRange(newList);
    mergedList.AddRange(existingList.Except(newList, new ListItemComparer()));
    return mergedList.OrderByDescending(x => x.Score).Take(10).ToList();
}

public class ListItemComparer : IEqualityComparer<ListItem>
{
    public bool Equals(ListItem x, ListItem y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(ListItem obj)
    {
        return obj.Name.GetHashCode();
    }
}

Вы можете назвать это так:

newList = CompareLists(existingList, newList);
3 голосов
/ 11 сентября 2010

Если вы ищете общее решение, не зависящее от языка, то вам нужна какая-то синхронизация данных упорядоченных списков. Основной алгоритм будет:

i1 = 0
i2 = 0
while (i1 < list1.size && i2 < list2.size)
{
  if (list1[i1] < list2[i2])
  {
    //list1[i1] is not in list2
    i1++
  }
  else if (list1[i1] > list2[i2])
  {
    //list2[i2] is not in list1
    i2++
  }
  else
  {
    //item is in both lists
    i1++
    i2++
  }
}
if (i1 < list1.size)
   //all remaining list1 items are not in list2
if (i2 < list2.size)
   //all remaining list2 items are not in list1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...