Відмінність у 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 має більше 1 поля?

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;
        }
    }
}

вибачте, що я не хотів використовувати рівність.
— Megha Jain

@MeghaJain Ну, буде використовуватися незалежно, як і GroupByпотрібне. Обидва способи використовуватимуть за замовчуванням, EqualityComparerякщо жодного не передбачено.
— Сервіс

9
Ну, виправте мене, якщо я помиляюся, але це чітке значення тут робиться в пам'яті, а не в БД? Не може це призвести до небажаного повного сканування?
— Кек

@Kek. Ні, через прибуток урожайності ви зупинитесь на першому виразному елементі. Зрештою, так, ви завантажите кожну клавішу в HashSet, але оскільки це IEnumerable у та IEnumerable, ви отримаєте лише ті елементи. Якщо ви говорите про LINQ для SQL, то так, це здійснить сканування таблиці.
— PRMan

12

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

Здається, що ви хочете цього:

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

Це вибере рядки, де Textунікальний.



3

Навколо цієї теми є багато дискусій.

Ви можете знайти один з них тут :

Однією з найпопулярніших пропозицій був метод розрізнення, який приймає лямбда-вираз як параметр, як вказував @Servy.

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


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 });


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.