Виберіть декілька полів зі списку в Linq


128

У ASP.NET C # у мене є структура:

public struct Data
{
    public int item1;
    public int item2;
    public int category_id;
    public string category_name;
}

і у мене є список таких. Я хочу вибрати category_idі category_name, запустивши DISTINCTі, нарешті, ORDERBYна category_name.

Ось що я маю зараз:

List<Data> listObject = getData();
string[] catNames = listObject
                    .Select(i=> i.category_name)
                    .Distinct()
                    .OrderByDescending(s => s)
                    .ToArray();

Це очевидно просто отримує назву категорії. Моє запитання полягає в тому, як я отримую кілька полів і в якій структурі даних я буду зберігати це (а не string[])?

EDIT

Використання списку конструкцій не встановлено в камені. Якщо було б доцільно змінити структуру резервних даних, щоб полегшити вибір (я буду писати їх багато), тоді я з радістю прийму рекомендації.


10
Хоча це не пов'язане зі стороною LINQ, я б настійно радив вам не використовувати змінні структури або публічні поля. Особисто я рідко створюю структури в першу чергу, але змінні структури просто задають проблеми.
Джон Скіт

@Jon Skeet Спасибі Я перетворять його на звичайний клас із приватними членами.
Чет

1
@Midhat: Змінні структури викликають всілякі проблеми, оскільки вони не ведуть себе так, як люди від них очікують. А публічні поля дають повну відсутність інкапсуляції.
Джон Скіт

@Jon Skeet Чи можете ви бути більш конкретними щодо підводних каменів змінних конструкцій або вказати мені на читання.
Midhat

2
@Midhat: Погляньте на stackoverflow.com/questions/441309/why-are-mutable-structs-evil для відправної точки.
Джон Скіт

Відповіді:


228

Анонімні типи дозволяють вибирати довільні поля в структурі даних, які сильно набираються пізніше у вашому коді:

var cats = listObject
    .Select(i => new { i.category_id, i.category_name })
    .Distinct()
    .OrderByDescending(i => i.category_name)
    .ToArray();

Оскільки вам (мабуть) потрібно зберігати його для подальшого використання, ви можете використовувати оператора GroupBy:

Data[] cats = listObject
    .GroupBy(i => new { i.category_id, i.category_name })
    .OrderByDescending(g => g.Key.category_name)
    .Select(g => g.First())
    .ToArray();

Я хочу використовувати розрізнення на 1 стовпчик і отримати декілька стовпців. ТАК як я можу це зробити?
Кішань Гаджар

1
Я ніколи не думав Selectпереходити на новий тип. У моєму випадку я вибрав нове KeyValuePair.
cjbarth

26
var selectedCategories =
    from value in
        (from data in listObject
        orderby data.category_name descending
        select new { ID = data.category_id, Name = data.category_name })
    group value by value.Name into g
    select g.First();

foreach (var category in selectedCategories) Console.WriteLine(category);

Редагувати : зробило це більше LINQ-ey!


Ха-ха, спасибі, ну, я ціную допомогу. Мабуть, це було не найскладніше питання у світі.
Чет

@IRBMe Вибачте, невелике запитання. Що таке «цінність»?
Фернандо С. Крус

23

Ви можете використовувати анонімний тип:

.Select(i => new { i.name, i.category_name })

Компілятор генерує код для класу з nameта category_nameвластивостями та повертає екземпляри цього класу. Ви також можете вручну вказати назви властивостей:

i => new { Id = i.category_id, Name = i.category_name }

Ви можете мати довільну кількість властивостей.


6

Ви можете вибрати кілька полів за допомогою linq Select, як показано вище в різних прикладах, це повернеться як анонімний тип. Якщо ви хочете уникнути цього анонімного типу, тут простий трюк.

var items = listObject.Select(f => new List<int>() { f.Item1, f.Item2 }).SelectMany(item => item).Distinct();

Я думаю, що це вирішує вашу проблему


5

Це завдання, для якого анонімні типи дуже добре підходять. Ви можете повернути об'єкти типу, які автоматично створює компілятор, які випливають із використання.

Синтаксис має таку форму:

new { Property1 = value1, Property2 = value2, ... }

Для вашого випадку спробуйте щось подібне:

var listObject = getData();
var catNames = listObject.Select(i =>
    new { CatName = i.category_name, Item1 = i.item1, Item2 = i.item2 })
    .Distinct().OrderByDescending(s => s).ToArray();

4
var result = listObject.Select( i => new{ i.category_name, i.category_id } )

Для цього використовуються анонімні типи, тому вам потрібно ввести ключове слово var, оскільки отриманий тип виразу заздалегідь не відомий.



3

Ви можете зробити це KeyValuePair, тому він поверне a "IEnumerable<KeyValuePair<string, string>>"

Отже, це буде так:

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name )).Distinct();

Це додає зайвої складності без користі
Матз

2
public class Student
{
    public string Name { set; get; }
    public int ID { set; get; }
}

class Program
{
  static void Main(string[] args)
    {
        Student[] students =
        {
        new Student { Name="zoyeb" , ID=1},
        new Student { Name="Siddiq" , ID=2},
        new Student { Name="sam" , ID=3},
        new Student { Name="james" , ID=4},
        new Student { Name="sonia" , ID=5}
        };

        var studentCollection = from s in students select new { s.ID , s.Name};

        foreach (var student in studentCollection)
        {
            Console.WriteLine(student.Name);
            Console.WriteLine(student.ID);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.