Различие в Linq на основе только одного поля таблицы

133

Я пытаюсь использовать .distinct в Linq, чтобы получить результат на основе одного поля таблицы (поэтому не требуется целые дублированные записи из таблицы).

Я знаю, как писать базовый запрос, используя следующие:

var query = (from r in table1
orderby r.Text
select r).distinct();

но мне нужны результаты, которые r.textне дублируются.

Мегха Джайн
источник
Вам необходимо указать, какое поле вы хотите выделить, см. Msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd,

Ответы:

300

Попробуй это:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

Это сгруппирует таблицу по Textи использует первую строку из каждой группы, в результате чего будут строки, в которых Textесть разные.

Дэниел Хилгарт
источник
2
Что делать, если в groupby больше одного поля?
6
@ user585440: В этом случае вы используете анонимный тип, например:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth
2
Да, вы правы, я это уже нашла. Спасибо, в любом случае. И я также обнаружил, что Select (x => x.First ()) может вызвать сбой. Лучше поменять на Select (x => x.FirstOrDefault ());
6
Мне пришлось использовать FirstOrDefault, иначе произошла ошибка времени выполнения
TruthOf42
2
@ TruthOf42 Это маловероятно. GroupByне создает пустых групп, см. мой предыдущий комментарий. Скорее всего, ваш код содержит больше, чем вы здесь видите. Может быть, у вас тоже Whereесть условие для First.
Дэниел Хилгарт,
26

MoreLinq имеет метод DistinctBy, который вы можете использовать:

Это позволит вам делать:

var results = table1.DistictBy(row => row.Text);

Реализация метода (за исключением проверки аргументов) следующая:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}
Servy
источник
извините, я не хотел использовать EquityComparer.
Megha Jain
@MeghaJain Ну, один будет использоваться независимо, так GroupByкак он тоже нужен. Оба метода будут использовать значение по умолчанию, EqualityComparerесли оно не указано.
Servy
9
Что ж, поправьте меня, если я ошибаюсь, но здесь это делается в памяти, а не в БД? Не могло ли это привести к нежелательному полному сканированию?
Kek
@Kek. Нет, из-за доходности вы остановитесь на первом отдельном элементе. В конце концов, да, вы загрузите каждый ключ в HashSet, но поскольку он IEnumerable входит и IEnumerable выходит, вы получите только эти элементы. Если вы говорите о LINQ to SQL, то да, это будет сканирование таблицы.
PRMan,
12

но мне нужны результаты, в которых r.text не дублируется

Похоже, вы этого хотите:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

Это выберет строки, в которых Textявляется уникальным.

Тим Шмелтер
источник
3

По этой теме ведется много дискуссий.

Вы можете найти один из них здесь :

Одним из самых популярных предложений был метод Distinct, принимающий лямбда-выражение в качестве параметра, как указал @Servy.

Главный архитектор C # Андерс Хейлсберг предложил здесь решение . Также объясняется, почему команда разработчиков фреймворка решила не добавлять перегрузку метода Distinct, который принимает лямбду.

TKharaishvili
источник
2

Судя по тому, что я нашел, ваш запрос в основном правильный. Просто измените «select r» на «select r.Text» и все, и это должно решить проблему. Вот как MSDN задокументировала, как это должно работать.

Пример:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();
Джош Паркс
источник
вы изменили оператор «select», который в данном случае может быть нежелательным
faza
1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });
BGS
источник
-2

попробуйте этот код:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
Hamidreza
источник
-5

Вы можете попробовать это:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

LucaGuerra
источник