2013-06-04 71 views
0

我創建了一個快速控制檯應用程序,它創建10000個年輕人和10000個老年人,並將它們添加到兩個單獨的列表中。然後,我會根據個性進行一些查詢以獲取信息。使用列表和Linq,編寫高效的代碼

class Program 
{ 
    static void Main(string[] args) 
    { 
     private Random random = new Random(); 
     private List<Person> youngerPersons = new List<Person>(); 
     private List<Person> olderPersons = new List<Person>(); 

     private long samePersonalityMatches = 0; 

     for (int i = 0; i < 10000; i++) 
     { 
      youngerPersons.Add(new Person(RandomString(10), DateTime.Now.ToString(), RandomString(4), random.Next(10, 50),(Person.PersonalityType)random.Next(0, 4), i)); 
     } 

     for (int i = 0; i < 10000; i++) 
     { 
      olderPersons.Add(new Person(RandomString(10), DateTime.Now.ToString(), RandomString(4), random.Next(51, 120),(Person.PersonalityType)random.Next(0, 4), i)); 
     } 

     //Example query 1 
     foreach (Person person in youngerPersons.Where(w => w.Id > 4567 && w.Age > 70)) 
     { 
      Console.WriteLine(person.Id); 
     } 

     //Example query 2 
     foreach (Person person in youngerPersons) 
     { 
      foreach (Person olderPerson in olderPersons) 
      { 
       if (person.Personality == olderPerson.Personality) 
       { 
        samePersonalityMatches++; 
       } 
      } 
     } 

     Console.WriteLine("Number of matches: " + samePersonalityMatches); 
    } 

    private static Random random = new Random((int)DateTime.Now.Ticks); 

    private static string RandomString(int size) 
    { 
     StringBuilder builder = new StringBuilder(); 
     char ch; 
     for (int i = 0; i < size; i++) 
     { 
      ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); 
      builder.Append(ch); 
     } 

     return builder.ToString(); 
    } 
} 

internal class Person 
{ 
    public enum PersonalityType 
    { 
     Funny = 0, 
     Boring = 1, 
     Serious = 2, 
     Grumpy = 3, 
     Normal = 4 
    } 

    public Person(string name, string dateofbirth, string nickname, int age, PersonalityType personalityType, int id) 
    { 
     this.Name = name; 
     this.Dateofbirth = dateofbirth; 
     this.Nickname = nickname; 
     this.Age = age; 
     this.Id = id; 
     this.Personality = personalityType; 
    } 

    public string Name { get; set; } 

    public string Dateofbirth { get; set; } 

    public string Nickname { get; set; } 

    public int Age { get; set; } 

    public int Id { get; set; } 

    public PersonalityType Personality { get; set; } 
} 

基本上,我想了解最佳實踐,以獲得性能最高的兩個示例查詢我放在代碼中。我已經閱讀了一些關於使用相交的性能相關材料,但我不確定哪個和何時最適合用來獲得最佳性能。這些列表有點OTT(大小明智),但它讓示例兩個更有趣的運行。

回答

3

一個很好,非常接近最佳狀態,我會像你一樣留下它(記住,程序員的時間比機器時間更昂貴)。

對於兩個你可以做得更好。您正在多次閱讀olderPersons列表,我們來看看是否可以將它歸結爲一次遍歷。

Dictionary<Personality, int> dict = 
    youngerPersons.GroupBy(p => p.Personality) 
        .ToDictionary(g => g.Key, g => g.Count()); 
long samePersonalityMatches = 
    olderPersons.Select(
        q => dict.ContainsKey(q.Personality) ? 
        dict[q.Personality] : 0 
       ) 
       .Sum(); 

然後,一旦我們看到這一點,我們應該對自己說,嘿,這看起來像一個hash join!然後,我們可以更清楚地寫:

long samePersonalityMatches = 
    youngerPersons.Join(
         olderPersons, 
         p => p.Personality, 
         q => q.Personality, 
         (p, q) => null 
       ) 
        .Count(); 

任何時候你看到的格局嵌套循環,比賽過外,內,你應該考慮的加入!

+0

一個連接做同樣的事情,並且簡單得多... –

+1

連接*是*相同的東西。我正在教育學。 – jason

3

第一個示例查詢很好,可能沒有什麼可以改善其性能。

在第二個查詢,你可以使用一個連接:

samePersonalityMatches = 
    youngerPersons.Join(olderPersons, 
         p => p.Personality, 
         p => p.Personality, 
         (left, right) => null) // the result doesn't really matter, 
               // since we just want the count 
        .Count(); 

或者,如果你喜歡的查詢語法:

samePersonalityMatches = 
    (from y in youngerPersons 
    join o in olderPersons 
     on y.Personality equals o.Personality 
    select null).Count(); 

聯接列舉每個列表只有一次,所以複雜度爲O(M + N) ,而不是O(M * N)

0

在這裏從傑森和托馬斯的具體答案假設(相當合理地考慮到你的問題措辭的方式)噸在獲得數據之前,你不知道這些問題。

我以爲我會指出,如果你確實知道你要問你的數據的問題,你可以繼續運行聚合,因爲你將年輕人和老年人添加到你的列表中,所以答案總是準備好。

這與選擇在數據庫中建立特定索引的動機類似。

相關問題