Pilih Beberapa Bidang dari Daftar di Linq


128

Dalam ASP.NET C # Saya memiliki sebuah struct:

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

dan saya punya Daftar itu. Saya ingin memilih category_iddan category_name, menjalankan DISTINCTdan akhirnya ORDERBYmenyala category_name.

Inilah yang saya miliki sekarang:

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

Ini jelas hanya mendapatkan nama kategori. Pertanyaan saya adalah, bagaimana cara mendapatkan beberapa bidang, dan struktur data apa yang akan saya simpan ini (bukan a string[])?

EDIT

Menggunakan daftar struct tidak diatur dalam batu. Jika akan disarankan untuk mengubah struktur data dukungan saya untuk membuat pemilihan lebih mudah (saya akan menulis banyak ini) maka saya dengan senang hati akan mengambil rekomendasi.


10
Meskipun tidak terkait dengan sisi LINQ, saya akan sangat menyarankan Anda untuk tidak menggunakan struct yang bisa berubah atau bidang publik. Secara pribadi saya jarang membuat struct di tempat pertama, tetapi struct bisa berubah hanya meminta masalah.
Jon Skeet

@ Jon Skeet Terima kasih. Saya akan mengubahnya menjadi kelas reguler dengan anggota pribadi.
Chet

1
@ Madhat: Structable bisa menyebabkan semua jenis masalah, karena mereka tidak berperilaku seperti yang diharapkan orang. Dan bidang publik sama sekali tidak memiliki enkapsulasi.
Jon Skeet

@ Jon Skeet. Bisakah Anda lebih spesifik dengan perangkap struct yang bisa berubah, atau arahkan saya ke bacaan.
Midhat

Jawaban:


228

Jenis anonim memungkinkan Anda untuk memilih bidang yang berubah-ubah menjadi struktur data yang sangat diketik dalam kode Anda:

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

Karena Anda (tampaknya) perlu menyimpannya untuk digunakan nanti, Anda bisa menggunakan operator GroupBy:

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

Saya ingin menggunakan yang berbeda pada 1 kolom dan mengambil beberapa kolom. Jadi bagaimana saya bisa melakukannya?
Kishan Gajjar

1
Saya tidak pernah berpikir untuk Selectmenjadi tipe baru. Dalam kasus saya, saya memilih yang baruKeyValuePair .
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);

Sunting : Jadikan lebih LINQ-ey!


Haha, terima kasih, well, saya sangat menghargai bantuannya. Tampaknya ini bukan pertanyaan yang paling sulit di dunia.
Chet

@IRBMe Maaf, pertanyaan kecil. Apa sebenarnya 'nilai' itu?
Fernando S. Kroes

23

Anda dapat menggunakan jenis anonim:

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

Compiler akan menghasilkan kode untuk kelas dengan namedan category_nameproperti dan mengembalikan instance dari kelas itu. Anda juga dapat secara manual menentukan nama properti:

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

Anda dapat memiliki sejumlah properti yang berubah-ubah.


6

Anda dapat memilih beberapa bidang menggunakan LINQ Pilih seperti yang ditunjukkan di atas dalam berbagai contoh ini akan kembali sebagai Jenis Anonim. Jika Anda ingin menghindari jenis anonim di sini adalah trik sederhana.

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

Saya pikir ini menyelesaikan masalah Anda


5

Ini adalah tugas yang jenis anonimnya sangat cocok. Anda dapat mengembalikan objek jenis yang dibuat secara otomatis oleh kompiler, disimpulkan dari penggunaan.

Sintaksnya berupa:

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

Untuk kasus Anda, cobalah sesuatu seperti berikut:

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

Ini menggunakan jenis anonim sehingga Anda harus kata kunci var, karena jenis ekspresi yang dihasilkan tidak diketahui sebelumnya.


3
(from i in list
 select new { i.category_id, i.category_name })
 .Distinct()
 .OrderBy(i => i.category_name);

3

Anda bisa menjadikannya sebagai KeyValuePair, jadi itu akan mengembalikan a "IEnumerable<KeyValuePair<string, string>>"

Jadi, akan seperti ini:

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

Ini menambah kompleksitas yang tidak perlu tanpa manfaat
Matze

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);
        }
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.