2017-02-20 4 views
0

У меня есть два списка, и я пытаюсь их объединить, и после слияния мой список должен быть в порядке возрастания по рангу.Объединить два списка и упорядочить объединенный список на основе ранга

Код:

public class Test 
    { 
     public int TestId { get; set; } 
     public List<VariantsRank> VariantsRanks { get; set; } 
    } 

    public class VariantsRank 
    { 
     public int VariantId { get; set; } 
     public string Name { get; set; } 
     public int Rank { get; set; } 
    } 
    public class Class1 
    { 
     public void Process() 
     { 
      var List1 = new Test(); 
      List1.TestId = 100; 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 10, Name = "V1", Rank = 0 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 11, Name = "V2", Rank = 1 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 12, Name = "V3", Rank = 2 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 13, Name = "V4", Rank = 3 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 14, Name = "V5", Rank = 4 }); 

      List1.VariantsRanks.Add(new VariantsRank { VariantId = 15, Name = "V6", Rank = 5 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 16, Name = "V7", Rank = 6 }); 
      List1.VariantsRanks.Add(new VariantsRank { VariantId = 17, Name = "V8", Rank = 7 }); 

      var List2 = new Test(); 
      List2.TestId = 100; 
      List2.VariantsRanks.Add(new VariantsRank { VariantId = 17, Name = "V8", Rank = 0 }); 
      List2.VariantsRanks.Add(new VariantsRank { VariantId = 15, Name = "V6", Rank = 1 }); 
      List2.VariantsRanks.Add(new VariantsRank { VariantId = 16, Name = "V7", Rank = 2 }); 
      List2.VariantsRanks.Concat(List1.VariantsRanks).GroupBy(x => x.VariantId).SelectMany(x => x.Take(1)).ToList(); 
     } 
    } 

Выход Я получаю:

VariantId = 10, Name = "V1", Rank = 0 
VariantId = 11, Name = "V2", Rank = 1 
VariantId = 12, Name = "V3", Rank = 2 
VariantId = 13, Name = "V4", Rank = 3 
VariantId = 14, Name = "V5", Rank = 4 

VariantId = 15, Name = "V6", Rank = 5 
VariantId = 16, Name = "V7", Rank = 6 
VariantId = 17, Name = "V8", Rank = 7 

Ожидаемый результат:

Теперь я бы например, для объединения списка 2 и для тех записей, которые соответствуют в списке1, тогда я хотел бы отдать приоритет спискам записей 2, поэтому v8, v6 и v7 списка 2 должны заменить записи списка 1 i.e v6, v7 и v8.

+0

Вы говорите: _expected, если вы увидите, то V8 находится на 5-м положении, потому что его ранг пятой в моей list2_ Но не V8 имеют ранг 0 в список 2? Также все VariantId в списке 2 всегда существует в списке 1? – Magnus

+0

@Magnus: Извините за ошибку.Я обновил свой вопрос –

+0

И если в списке2 нет соответствующего элемента, должен ли он быть включен в конечный результат? Например, если в списке2 был элемент 'v505'? – Magnus

ответ

3

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

Я хотел бы начать с подготовки очереди упорядоченных матчей из второго списка:

var matchQueue = new Queue<VariantsRank>(
    from r2 in List2.VariantsRanks 
    join r1 in List1.VariantsRanks on r2.VariantId equals r1.VariantId 
    orderby r2.Rank 
    select r2); 

затем HashSet с согласованными ключами:

var matchSet = new HashSet<int>(matchQueue.Select(r2 => r2.VariantId)); 

Мы собираемся обрабатывать первый список в порядок, то для каждого элемента будет использоваться matchSet, чтобы определить, есть ли совпадение, и если да, примет следующее совпадение в порядке с использованием подготовленного matchQueue.

Затем мы добавим непревзойденные элементы из второго списка по порядку. Наконец, мы будем перебирать результирующую последовательность (которая должна быть правильно упорядочена с предыдущих шагов) и обновлять ряды.

Все, что в переводе на LINQ выглядит следующим образом:

var result = List1.VariantsRanks 
    .OrderBy(r1 => r1.Rank) 
    .Select(r1 => matchSet.Contains(r1.VariantId) ? matchQueue.Dequeue() : r1) 
    .Concat(List2.VariantsRanks 
    .Where(r2 => !matchSet.Contains(r2.VariantId)) 
    .OrderBy(r2 => r2.Rank)) 
    .Select((r, i) => new VariantsRank { VariantId = r.VariantId, Name = r.Name, Rank = i }) 
    .ToList(); 
3

Это первое решение, которое пришло мне в голову:

var result=List1.VariantsRanks.Union(List2.VariantsRanks) 
       .GroupBy(e=>e.VariantId) 
       .Select(g=>g.OrderBy(e=>e.Rank).FirstOrDefault()) 
       .OrderBy(e=>e.RankId); 

Объяснение:

  1. Регистрация как список
  2. группа вариант по VariantId
  3. Заказать каждую группу по Rank и сохранить только первый
  4. Заказать приведенный список по Rank
+0

Ваш последний заказ у вас будет ранг? –

+0

точно, это заказать первый элемент, который я получаю от каждой группы. – octavioccl

+0

Упомянуто для ваших добрых усилий по оказанию мне помощи. Извините, но по ошибке я поставил неправильный порядок в моем втором списке. См. Мой обновленный вопрос для List2 и извините еще раз , –

Смежные вопросы