Відмінність у 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.