简体   繁体   中英

C# : How to sort a list of object based on a list of string

I'm having two list like

 List<String> l_lstNames = new List<String> { "A1", "A3", "A2", "A4", "A0" };

List<Test> l_lstStudents = new List<Test> 
                            { new Test { Age = 20, Name = "A0" }, 
                              new Test { Age = 21, Name = "A1" }, 
                              new Test { Age = 22, Name = "A2" }, 
                              new Test { Age = 23, Name = "A3" }, 
                              new Test { Age = 24, Name = "A4" }, 
                            };

Where Test is class like

 public class Test
    {
        public String Name;
        public Int32 Age;
    }

I need to sort the items in the l_lstStudents based on the l_lstNames . So the sorted list will be like,

List<Test> l_lstStudents = new List<Test> 
                        {  new Test { Age = 21, Name = "A1" }, 
                           new Test { Age = 23, Name = "A3" }, 
                           new Test { Age = 22, Name = "A2" }, 
                           new Test { Age = 24, Name = "A4" }, 
                           new Test { Age = 20, Name = "A0" }, 
                        };

Now i'm using for to do this.

Like

  1. Create a new list of Test objects.

  2. Iterate the loop for l_lstNames and fetch the Test object from l_lstStudent and add the same to the newly created list. Finally assign the new list to l_lstStudent

Please help me to do this in a simple way ( Linq or Lambda)

Try this:

l_lstStudents = l_lstStudents.OrderBy(s => l_lstNames.IndexOf(s.Name)).ToList()

I think that expresses the intention quite clearly.

How about

var studentLookup = l_lstStudents.ToDictionary(s => s.Name, s => s);
return l_lstNames.Select(n => studentLookup[n]);

Try something like:

List<String> l_lstNames = new List<String> { "A1", "A3", "A2", "A4", "A0" };

List<Test> l_lstStudents = new List<Test> 
                            { new Test { Age = 20, Name = "A0" }, 
                              new Test { Age = 21, Name = "A1" }, 
                              new Test { Age = 22, Name = "A2" }, 
                              new Test { Age = 23, Name = "A3" }, 
                              new Test { Age = 24, Name = "A4" }, 
                            };

// We transform the list in a dictionary to make it faster to access.
// The first Select creates a new object with the index of the name and 
// the ToDictionary creates the Dictionary.
// Note that technically on a small list (like 5 elements) 
// it's probably faster to IndexOf directly the List... 
// This is the problem of premature optimization :-) :-)
// If you know the list will always be 5 elements then probably 
// IndexOf is more than enough.
var dict = l_lstNames.Select((p, i) => new { Index = i, Name = p })
                     .ToDictionary(p => p.Name, p => p.Index);

// We sort it. This works because 3 < 5 => 3 - 5 < 0, 5 > 3 => 5 - 3 > 0, 5 == 5 => 5 - 5 == 0
l_lstStudents.Sort((p, q) => dict[p.Name] - dict[q.Name]);

// We could do something like and it would be clearer.
l_lstStudents.Sort((p, q) => dict[p.Name].CompareTo(dict[q.Name]));

Using

l_lstStudents = l_lstStudents.OrderBy(x => l_lstNames.IndexOf(x.Name)).ToList();

in a small test program

public class Test
{
    public String Name;
    public Int32 Age;
}

class Program
{
    static void Main(string[] args)
    {
        List<String> l_lstNames = new List<String> { "A1", "A3", "A2", "A4", "A0" };

        List<Test> l_lstStudents = new List<Test> 
                                    { new Test { Age = 20, Name = "A0" }, 
                                      new Test { Age = 21, Name = "A1" }, 
                                      new Test { Age = 22, Name = "A2" }, 
                                      new Test { Age = 23, Name = "A3" }, 
                                      new Test { Age = 24, Name = "A4" }, 
                                    };

        l_lstStudents = l_lstStudents.OrderBy(x => l_lstNames.IndexOf(x.Name)).ToList();
    }
}

results in

Age     21      int  
Name    "A1"    string 

Age     23      int  
Name    "A3"    string  

Age     22      int  
Name    "A2"    string 

Age     24      int  
Name    "A4"    string  

Age     20      int  
Name    "A0"    string 

and thus is:

List<Test> l_lstStudents = new List<Test> 
                        {  new Test { Age = 21, Name = "A1" }, 
                           new Test { Age = 23, Name = "A3" }, 
                           new Test { Age = 22, Name = "A2" }, 
                           new Test { Age = 24, Name = "A4" }, 
                           new Test { Age = 20, Name = "A0" }, 
                        };

Try this. Putting it in a dictionary may save some look up time:

int i = 0;
Dictionary<string, int> ordinalValues = l_lstNames.ToDictionary(name => name, name => i++);
var sortedStudents = l_lstStudents.OrderBy( a => ordinalValues[a.Name]).ToList();

Try out with following code:

 l_lstStudents = (from name in l_lstNames
                  join student in l_lstStudents
                  on name equals student.Name
                  select student).ToList<Test>();
var newList = l_lstNames.Join(l_lstStudents, 
    s => s, 
    test => test.Name, 
    (s, test) => new Test { Name = s, Age = test.Age }
    ).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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