简体   繁体   English

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

[英]Select Multiple Fields from List in Linq

In ASP.NET C# I have a struct:在 ASP.NET C# 中,我有一个结构:

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

and I have a List of those.我有一个清单。 I want to select category_id and category_name , running a DISTINCT and finally an ORDERBY on category_name .我想选择category_idcategory_name ,运行DISTINCT最后一个ORDERBYcategory_name

Here's what I have now:这是我现在所拥有的:

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

This obviously just gets the category name.这显然只是获取类别名称。 My question is, how do I get multiple fields, and what data structure will I store this in (not a string[] )?我的问题是,如何获取多个字段,以及将其存储在什么数据结构中(不是string[] )?

EDIT编辑

Using a list of structs is not set in stone.使用结构列表并不是一成不变的。 If it would be advisable to change my backing data structure to make selects easier (I'll be writing a lot of these) then I'd gladly take recommendations.如果建议更改我的支持数据结构以使选择更容易(我将编写很多这样的内容),那么我很乐意接受建议。

Anonymous types allow you to select arbitrary fields into data structures that are strongly typed later on in your code:匿名类型允许您将任意字段选择到稍后在代码中强类型的数据结构中:

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

Since you (apparently) need to store it for later use, you could use the GroupBy 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();
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);

Edit : Made it more LINQ-ey!编辑:让它更加 LINQ-ey!

You could use an anonymous type:您可以使用匿名类型:

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

The compiler will generate the code for a class with name and category_name properties and returns instances of that class.编译器将为具有namecategory_name属性的类生成代码并返回该类的实例。 You can also manually specify property names:您还可以手动指定属性名称:

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

You can have arbitrary number of properties.您可以拥有任意数量的属性。

You can select multiple fields using linq Select as shown above in various examples this will return as an Anonymous Type.您可以使用 linq Select 选择多个字段,如上面的各种示例所示,这将作为匿名类型返回。 If you want to avoid this anonymous type here is the simple trick.如果你想避免这种匿名类型,这里有一个简单的技巧。

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

I think this solves your problem我认为这可以解决您的问题

This is task for which anonymous types are very well suited.这是匿名类型非常适合的任务。 You can return objects of a type that is created automatically by the compiler, inferred from usage.您可以返回由编译器自动创建的类型的对象,从用法推断。

The syntax is of this form:语法是这种形式:

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

For your case, try something like the following:对于您的情况,请尝试以下操作:

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

这使用匿名类型,因此您必须使用 var 关键字,因为事先不知道表达式的结果类型。

You can make it a KeyValuePair, so it will return a "IEnumerable<KeyValuePair<string, string>>"您可以将其设为 KeyValuePair,因此它将返回"IEnumerable<KeyValuePair<string, string>>"

So, it will be like this:所以,它会是这样的:

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name )).Distinct();
(from i in list
 select new { i.category_id, i.category_name })
 .Distinct()
 .OrderBy(i => i.category_name);
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);
        }
    }
}

Given List<MyType1> internalUsers and List<MyType2> externalUsers , based on the shared key of an email address...给定List<MyType1> internalUsersList<MyType2> externalUsers ,基于电子邮件地址的共享密钥...


For C# 7.0+:对于 C# 7.0+:

var matches = (
    from i in internalUsers
    join e in externalUsers
    on i.EmailAddress.ToUpperInvariant() equals e.Email.ToUpperInvariant()
    select (internalUser:i, externalUser:e)
).ToList();

Which gives you matches as a List<(MyType1, MyType2)> .它为您提供了matches List<(MyType1, MyType2)>

From there you can compare them if you wish:如果您愿意,您可以从那里比较它们:

var internal_in_external = matches.Select(m => m.internalUser).ToList();
var external_in_internal = matches.Select(m => m.externalUser).ToList();

var internal_notIn_external = internalUsers.Except(internal_in_external).ToList();
var external_notIn_internal = externalUsers.Except(external_in_internal).ToList();

internal_in_external and internal_notIn_external will be of type List<MyType1> . internal_in_externalinternal_notIn_external将是List<MyType1>类型。

external_in_internal and external_notIn_internal will be of type List<MyType2> external_in_internalexternal_notIn_internal的类型为List<MyType2>


For versions of C# prior to 7.0:对于 7.0 之前的 C# 版本:

var matches = (
    from i in internalUsers
    join e in externalUsers
    on i.EmailAddress.ToUpperInvariant() equals e.Email.ToUpperInvariant()
    select new Tuple<MyType1, MyType2>(i, e)
).ToList();

Which gives you matches as a List<Tuple<MyType1, MyType2>> .它为您提供matches List<Tuple<MyType1, MyType2>>

From there you can compare them if you wish:如果您愿意,您可以从那里比较它们:

var internal_in_external = matches.Select(m => m.Item1).ToList();
var external_in_internal = matches.Select(m => m.Item2).ToList();

var internal_notIn_external = internalUsers.Except(internal_in_external).ToList();
var external_notIn_internal = externalUsers.Except(external_in_internal).ToList();

internal_in_external and internal_notIn_external will be of type List<MyType1> . internal_in_externalinternal_notIn_external将是List<MyType1>类型。

external_in_internal and external_notIn_internal will be of type List<MyType2> external_in_internalexternal_notIn_internal的类型为List<MyType2>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM