2016-04-08 2 views
3

Моя модель:Сортировка списка <T> другой список <T>

class Person 
{ 
    public int Id {get; set; } 
    public string Name {get; set; } 
} 

У меня есть две коллекции. И я хотел бы сортировать toBeSortedList как etalonList:

List<Person> etalonList = new List<Person>() 
{ 
    new Person() { Id=10, Name="Jon"}, 
    new Person() { Id=4, Name="Ben"}, 
    new Person() { Id=11, Name="Magnus"}, 
    new Person() { Id=8, Name="Joseph"}, 
}; 

List<Person> toBeSortedList = new List<Person>() 
{ 
    new Person() { Id=11, Name="Magnus"}, 
    new Person() { Id=4, Name="Ben"},     
    new Person() { Id=10, Name="Jon"}, 
    new Person() { Id=8, Name="Joseph"}, 
}; 

Я пробовал:

var orderedByIdList = tobeSortedList.OrderBy(x => etalonList.IndexOf(x.Id)); 

Но я встретил такую ​​ошибку:

cannot convert from 'int' to 'SOConsoleApplication.Person'

Может быть, у вас есть еще предложения ?

+1

tobeSortedList.OrderBy (х => etalonList.IndexOf (x.Id)) ToList();. – CodeConstruct

+1

@CodeConstruct Это тоже не сработает. –

+0

Вы должны отдать это классу (Лицо) – CodeConstruct

ответ

3

Я бы сначала создать словарь из etalonList для того, чтобы ускорить сортировку:

int index; 
var etalonDictionary = etalonList.ToDictionary(k => k.Id, v => index++); 

Затем найдите обратно ID из словаря и использовать его для сортировки:

var sortedList = toBeSortedList.OrderBy(x => etalonDictionary[x.Id]).ToList(); 
+0

Если вы все равно используете хэш-таблицу, вы также можете легко избежать сортировки. Создайте словарь из toBeSortedList, а затем используйте 'etalonList.Select (p => dict [p.Id])' – Joren

2

List.IndexOf принимает объект в качестве аргумента и возвращает его индекс. Вы передаете int -значение, которое является Id. Это не компилируется.

Вы можете переопределить Equals + GethashCode и передать x вместо x.Id. Но я предпочел бы List.FindIndex в этом случае:

var orderedByIdList = toBeSortedList 
    .OrderBy(x => etalonList.FindIndex(p => p.Id == x.Id)); 

Вот переопределение Equals подход, который позволяет использовать IndexOf:

class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     if(ReferenceEquals(obj, this)) 
      return true; 
     Person other = obj as Person; 
     if (other == null) 
      return false; 
     return other.Id == this.Id; 
    } 

    public override int GetHashCode() 
    { 
     return Id; 
    } 
} 

Сейчас это тоже работает:

var orderedByIdList = toBeSortedList 
    .OrderBy(x => etalonList.IndexOf(x)); 
1

Я предполагаю, что некоторые значения в etalonList отсутствуют в toBeSortedList, потому что во всех остальных случаях вопрос не вызывает чувства e:

  1. toBeSortedList содержит элементы, не включенные в etalonList. В этом случае проблема недоказана; как бы вы заказали новых членов списка?
  2. toBeSortedList содержит точно такие же члены etalonList имеет. В этом случае просто верните etalonList или дублируйте его.

Наивный, но простой способ заказать toBeSortedList заключается в следующем (обратите внимание, что я предполагаю, что случай 1 не представляется возможным):

static IEnumerable<T> OrderBy(this IEnumerable<T> list, IEnumerable<T> guideList) 
{ 
    foreach (var member in guideList) 
    { 
     if (toBeSortedList.Contains(member)) 
      yield return member; 
    } 
} 

var orderedList = toBeSortedList.OrderBy(etalonList).ToList(); 

Не выполняет все, что хорошо, но если списки не очень долго, он должен это делать.

1

Вам не нужен обычный сортировка в этом случае вообще. Вы можете просто join эталон с целью и спроектировать целевые элементы.Если эталон не содержит всех целей, вы можете конкатенировать несуществующие элементы либо в начале, либо в конце отсортированной последовательности, в конце концов применяя некоторый дополнительный порядок.

В обоих случаях вы получите оперативную сложность времени O (N).

Вот LINQ, что помещает несуществующие элементы в конце:

var orderedByIdList = 
    (from a in etalonList join b in toBeSortedList on a.Id equals b.Id select b) 
    .Concat 
    (from a in toBeSortedList join b in etalonList on a.Id equals b.Id into b where !b.Any() select a) 
    .ToList(); 
1
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, IEnumerable<T> guide) { 
     var toBeSorted = new HashSet<T>(list); 
     return guide.Where(member => toBeSorted.Contains(member)); 
    } 
Смежные вопросы