2016-08-16 2 views
0

Учитывая последовательность, как показано ниже: -Как удалить дубликаты в середине

var list = new[] {"1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a"}.Select(x => new { P1 = x.Substring(0,1), P2 = x.Substring(1,1)}); 

Я хотел бы, чтобы удалить дубликаты в «средний», чтобы в итоге: -

var expected = new[] {"1a", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a"}.Select(x => new { P1 = x.Substring(0, 1), P2 = x.Substring(1, 1) }); 

Таким образом, любые повторы более двух разделяются. Важно, чтобы я получил первый и последний дубликат.

+0

Вы можете использовать 'GroupBy', так как он сохраняет порядок (http://stackoverflow.com/questions/1452507/linq -to-objects-do-groupby-preserve-order-of-elements) или 'Aggregate'. –

ответ

1

Для тех, кто не агрегирует и хотите супер короткий ответ, используя закрытие здесь:

var data = new[] { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "1e", "5a", "6a", "7a", "7b", "8a" }; 
char priorKey = ' '; 
int currentIndex = 0; 

var result2 = data.GroupBy((x) => x[0] == priorKey ? new { k = x[0], g = currentIndex } : new { k = priorKey = x[0], g = ++currentIndex }) 
    .Select(i => new[] { i.First(), i.Last() }.Distinct()) 
    .SelectMany(i => i).ToArray(); 

Hat Подсказка для @Slai для кода это на основе (я добавил фикс для прерывистого группа выпуска.)


Вот как это сделать с помощью агрегата. Я не тестировал все краевые случаи ... только ваши тестовые примеры.

var list = new[] { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a" } 
      .Aggregate(new { result = new List<string>(), first = "", last = "" }, 
       (store, given) => 
       { 
       var result = store.result; 
       var first = store.first; 
       var last = store.last; 

       if (first == "") 
        // this is the first one. 
        first = given; 
       else 
       { 
        if (first[0] == given[0]) 
        last = given; 
        else 
        { 
        result.Add(first); 
        if (last != "") 
         result.Add(last); 
        first = given; 
        last = ""; 
        } 

       } 
       return new { result = result, first = first, last = last }; }, 
       (store) => { store.result.Add(store.first); if (store.last != "") store.result.Add(store.last); return store.result; }) 
      .Select(x => new { P1 = x.Substring(0,1), P2 = x.Substring(1,1)}); 

Я создаю объект для хранения списка до сих пор и первого и последнего из известных до сих пор.

Затем я просто применяю логику, чтобы удалить средний материал.

1

Группы по первому символу и взять первый и последний элемент каждой группы:

var list = "1a 1b 1c 1d 2a 3a 4a 4b 5a 6a 7a 7b 8a".Split(); 

var result = list.GroupBy(i => i[0]) 
    .Select(i => new[] { i.First(), i.Last() }.Distinct()) 
    .SelectMany(i => i).ToArray(); 

Debug.Print(string.Join("\", \"", result)); 
// { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a" } 
+0

Ваш ответ более краткий, чем у Хоганов, но он не позволяет повторения, например. var list = "1a 1b 1c 1d 2a 3a 4a 4b 1e 5a 6a 7a 7b 8a". При этом я использовал ваш код в сочетании с https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/GroupAdjacent.cs для достижения моей цели. Спасибо за указатель, я думал о GroupByUntil или что-то в этом роде. – user630190

+0

@ user630190 Я думаю, вы имеете в виду «разделение несмежных групп», когда вы говорите повторение. поэтому приведенный вами пример должен возвращать как 1a 1d, так и позже 1e. – Hogan

+0

Yup, правильный. Моя ошибка за то, что вы не включили его. – user630190