从Linq的列表中选择多个字段


128

在ASP.NET C#中,我有一个结构:

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

我有一个清单。我要选择category_idcategory_name,运行的DISTINCT最后一个ORDERBYcategory_name

这是我现在所拥有的:

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

这显然只是获得类别名称。我的问题是,如何获取多个字段,以及将其存储在什么数据结构中(而不是string[])?

编辑

使用结构列表并不是一成不变的。如果建议更改我的支持数据结构以使选择更容易(我将编写很多此类记录),那么我很乐意提出建议。


10
尽管它与LINQ无关,但我强烈建议您不要使用可变结构或公共字段。就我个人而言,我很少首先创建结构,但是可变结构只是自找麻烦。
乔恩·斯基特

@乔恩·斯基特谢谢。我将其转换为具有私人成员的普通班。
切特

1
@Midhat:可变结构会导致各种问题,因为它们的行为不像人们期望的那样。公共领域完全缺乏封装。
乔恩·斯基特

@乔恩·斯基特 您能更具体地说明可变结构的陷阱吗,还是请您参考一下。
Midhat的

Answers:


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列上使用distinct,并检索多个column.SO,我该怎么办?
Kishan Gajjar 2012年

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对不起,小问题。到底什么是“价值”?
Fernando S. Kroes

23

您可以使用匿名类型:

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

编译器将使用namecategory_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
(from i in list
 select new { i.category_id, i.category_name })
 .Distinct()
 .OrderBy(i => i.category_name);

3

您可以将其设置为KeyValuePair,这样它将返回一个 "IEnumerable<KeyValuePair<string, string>>"

因此,它将是这样的:

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

这增加了不必要的不​​必要的复杂性
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);
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.