Как получить второй повторяющийся элемент из коллекции объектов, используя LINQ для объекта - PullRequest
2 голосов
/ 10 июля 2010

У меня есть эта коллекция, например:

1: A

2: B

3: A

4: C

5: A

6: C

Я хочу получить второй повторяющийся элемент из этой коллекции в запросе LINQ,

требуемый результат: 3:А, 6: С

Ответы [ 2 ]

2 голосов
/ 10 июля 2010

Немного сложно, но работает:

int occ = 1; // 1 if you want the 2nd occurrence, 2 if you want the 3rd etc...
var nRepeatingElements = list.Select((x, idx) => new { Index = idx, Value = x })
                                .GroupBy(x => x.Value)
                                .Where(g => g.Count() > occ)
                                .Select(x => x.ElementAt(occ))
                                .ToList();

Возвращает список с:

[Index:2 , Value: 'A']
[Index:5 , Value: 'C']

нотабене

Индекс на 1 ниже, чем желаемое решение (потому что индекс основан на 0). Но его действительно легко увеличить, даже в первом LINQ. Выберите, если хотите:

Select((x, idx) => new { Index = idx+1, Value = x })
1 голос
/ 10 июля 2010
IEnumerable<Item> result =
  from item in items
  group item by item.Key into g
  let secondItem = g.Skip(1).Take(1) //.ToList()
  where secondItem.Any()
  select secondItem.First()

Вызов ToList - это оптимизация, предотвращающая повторное вычисление secondItem от g дважды. Возможно, это не имеет значения, поскольку мы пропускаем только 1, но может иметь значение, если мы начнем пропускать 100.


Вот еще одно решение с использованием Where и захваченной переменной.

HashSet<Item.Key> seenIt = new HashSet<Item.Key>();
HashSet<Item.Key> returnedIt = new HashSet<Item.Key>();

IEnumerable<Item> result =
  items.Where(item => 
{
  key = Item.Key;
  if (!seenIt[key])
  {
    seenIt.Add(key);
  }
  else if (!returnedIt[key])
  {
    returnedIt.Add(key)
    return true;
  }
  return false;
});
...