Select Multiple Fields from List in Linq

C#LinqData Structures

C# Problem Overview


In ASP.NET C# I have a struct:

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.

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[])?

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.

C# Solutions


Solution 1 - C#

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:

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

Solution 2 - C#

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!

Solution 3 - C#

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. You can also manually specify property names:

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

You can have arbitrary number of properties.

Solution 4 - C#

You can select multiple fields using linq Select as shown above in various examples this will return as an Anonymous Type. 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

Solution 5 - C#

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();

Solution 6 - C#

You can make it a KeyValuePair, so it will return a "IEnumerable<KeyValuePair<string, string>>"

So, it will be like this:

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

Solution 7 - C#

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

This uses anonymous types so you must the var keyword, since the resulting type of the expression is not known in advance.

Solution 8 - C#

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

Solution 9 - C#

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

Solution 10 - C#

Given List<MyType1> internalUsers and List<MyType2> externalUsers, based on the shared key of an email address...


For 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)>.

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>.

external_in_internal and external_notIn_internal will be of type List<MyType2>


For versions of C# prior to 7.0:

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>>.

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>.

external_in_internal and external_notIn_internal will be of type List<MyType2>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChetView Question on Stackoverflow
Solution 1 - C#JasonView Answer on Stackoverflow
Solution 2 - C#IRBMeView Answer on Stackoverflow
Solution 3 - C#mmxView Answer on Stackoverflow
Solution 4 - C#AR MView Answer on Stackoverflow
Solution 5 - C#NoldorinView Answer on Stackoverflow
Solution 6 - C#VictorView Answer on Stackoverflow
Solution 7 - C#Paul van BrenkView Answer on Stackoverflow
Solution 8 - C#Joe ChungView Answer on Stackoverflow
Solution 9 - C#Zoyeb ShaikhView Answer on Stackoverflow
Solution 10 - C#Danny BeckettView Answer on Stackoverflow