2013-10-21 126 views
4

从我可以告诉LINQ和lambda表达式是去解决我的特定问题的方法。在我的办公室,我有一个2维数组[IM长度] [2宽度]的IM日志列表,以便我可以看到谁是IM的谁。但日志由3位用户ID组成,而不是实际名称。如何加入2个列表,其中一个列表包含2个元素?

arrIMLog[x][1] 

因此,日志条目可能是这样的arrIMLog [0] [0] = 353和arrIMLog [0] [1] = 563意味着用户353 IM'ed用户563.然后,我有一个用户ID列表,我想知道他们通过日志刷新了哪些用户ID。

lstSuspects 

作为一个例子,lstSuspects(1)= 353,lstSuspects(2)= 563,等。我想创建一个新的和简单的列表,lstSuspectsContacted,使得我可以找出哪些唯一用户ID的每个人在lstSuspects上已经联系过(时间没有关系,但是)。我该怎么做呢?

var lstSuspectsContacted = (from x in arrIMLog 
          join y in lstSuspects 
      on arrIMLog[0] or arrIMLog[1] equals lstSuspects // join criteria 
      select new { arrIMLog[0] or arrIMLog[1]}).ToList(); 

时遇到的困难是,我希望选择任一[0]或[1]中的阵列取决于是否有与在arrIMLog另一元件[1 lstSuspects之间的匹配元件]或[0]。我不知道如何做到这一点。

+0

我不认为你关心的是lambda表达式。 Linq是你正在寻找的唯一标签。 – user1306322

+0

是的,AB被视为与BA相同,IM的方向对我来说并不重要。现在唯一重要的是A和B根据IM日志已经彼此联系。我试图找出谁与谁交谈,发件人/收件人的区别对我来说并不重要。 – phan

+0

也许你可以用更多但更简单的步骤来使用非linq表达式,比如foreach循环和if-checks?为什么它必须如此复杂? – user1306322

回答

1

下面是可能似乎更冗长,但会通过定义您的日志和犯罪嫌疑人POCO更扩展以及可读

就启动了一个解决方案。

public class Log 
    { 
     /// <summary> 
     /// Person initiating the contact 
     /// </summary> 
     public int From { get; set; } 

     /// <summary> 
     /// Person that was contacted 
     /// </summary> 
     public int To { get; set; } 
    } 

    public class SuspectConnection 
    { 
     public int SuspectId { get; set; } 

     public List<int> Contacts { get; set; } 
    } 

然后,您可以很容易地找到使用LINQ的连接。

var suspectConnections = new List<SuspectConnection>(); 

    foreach (var suspect in suspects) 
    { 
     var connection = new SuspectConnection() { SuspectId = suspect }; 

     connection.Contacts = logs.Where(x => x.From == suspect || x.To == suspect).Select(x => x.From == suspect ? x.To : x.From).ToList(); 
     suspectConnections.Add(connection); 
    } 
+0

我注意到你对From和To进行了区分。我该如何做到这一点,以便如果From或To包含SuspectId,我们希望将其他元素To或From添加到名为suspectConnections的List中?另外,POCO代表什么? – phan

+1

POCO代表Plain Old CLR对象,它基本上意味着一个普通的.NET类(例如Log和SuspectConnection类)。如果通过使用C#条件运算符http://msdn.microsoft.com/en-us/library/ty67wk28.aspx将suspectId显示在“收件人”或“来自”中,则可以添加其他元素。 'connection.Contacts = logs.Where(x => x.From == suspect || x.To == suspect).Select(x => x.From == suspect?x.To:x.From).ToList ();' –

+0

谢谢你的解释。 – phan

1

这里是一个使用lambda加入快速去。注意我为联系对中的每个联系人使用了两个联接。 我认为这也是最有效的解决方案。

int[][] log = new int[][] {new int[]{1,2},new int[]{2,1},new int[]{1,3},new int[]{2,3},new int[]{3,4},new int[]{4,1}}; 
List<Suspect> Suspects = new List<Suspect>(){new Suspect(){SuspectId = 1, Name = "Bob"},new Suspect(){SuspectId = 2, Name = "Frank"},new Suspect(){SuspectId = 3, Name = "Jimmy"},new Suspect(){SuspectId = 4, Name = "DrEvil"}}; 


       //order the contact pairs as 2 --> 1 is the same as 1 --> 2 
var q = log.Select (x => x.OrderBy (o => o)) 
       // Put contact record into an object which we have an IComparable for 
      .Select (s => new Contact(){A = s.ElementAt(0),B= s.ElementAt(1) }) 
       //Now eliminate the duplicates 
      .Distinct(new ContactComparer()) 
       //get the Name for contact A 
      .Join(Suspects, contactKey => contactKey.A, suspectKey => suspectKey.SuspectId,(c,s) => new Contact{A = c.A, AName = s.Name, B = c.B}) 
       //get the Name for contact B 
      .Join(Suspects, contactKey => contactKey.B, suspectKey => suspectKey.SuspectId,(c,s) => new Contact{A = c.A, AName = c.AName, B = c.B, BName = s.Name}) 
      .ToList(); 



//Classes that were used: 

public class Contact 
{ 

    public int A { get; set; } 
    public String AName { get; set; } 
    public int B { get; set; } 
    public String BName { get; set; } 

} 

public class Suspect 
{ 
    public int SuspectId { get; set; } 
    public String Name { get; set; } 
} 



//We will use this in the .Distinct() linq method, to find the (and remove) the duplicates 
public class ContactComparer : IEqualityComparer<Contact> 
{   
    public bool Equals(Contact x, Contact y) 
    { 

     //Check whether the compared objects reference the same data. 
     if (Object.ReferenceEquals(x, y)) return true; 

     //Check whether any of the compared objects is null. 
     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 

     //Check whether the id fields are equal. 
     return x.A == y.A && x.B == y.B; 
    } 

     public int GetHashCode(Contact contact) 
    { 
     //Check whether the object is null 
     if (Object.ReferenceEquals(contact, null)) return 0; 

     //Get hash code for the Name field if it is not null. 
     long contactA = contact.A == null ? 0 : contact.A; 
     long contactB = contact.B == null ? 0 : contact.A;  

     //Calculate the hash code for the product. 
     return (int)((contactA + contactB) % int.MaxValue); 
    }  

} 

结果:

Result

+0

谢谢达西。你的答案和我接受的答案一样好,我从你的例子中学到了新的概念。这就是说,我选择了Jun的答案,因为我觉得他们都一样好,但是他第一时间回答。对我来说这是一个艰难的选择。再次感谢您的出色解决方案。 – phan

+0

没问题。只要知道他的解决方案有更大的计算复杂性(即在更大数据量下会更糟糕) – DarcyThomas

+0

我认为Jun Wei Lee的解决方案是O:m * n。弗林德伯格的解决方案是O:n + m(O:n),这与我的相同。 – DarcyThomas

1

一个步进开箱,因为我永远不会把这个作为一个LINQ的问题解决它的办法。我正在做的是将其重塑为网络结构。而且我们只会遍历一次日志,如果我们正在查看大型数据集,这可能会成为一个问题。

void ShowCommunication(int[][] communication, int[] suspects) 
    { 
     var table = new Dictionary<int, Suspect>(); 

     // We are going through everyone, though 
     // communication.Where(t => suspects.Contains(t[0]) || suspects.Contains(t[1]))   
     // could speed it up, although that leaves us with an incomplete graph 
     foreach (var chat in communication) 
     { 
      if (!table.ContainsKey(chat[0])) table[chat[0]] = new Suspect(chat[0]); 
      if (!table.ContainsKey(chat[1])) table[chat[1]] = new Suspect(chat[1]); 

      // Remove the if-statement if you want the communication in order 
      if (!table[chat[0]].CoSuspects.Contains(table[chat[1]])) 
      { 
      table[chat[0]].CoSuspects.Add(table[chat[1]]); 
      table[chat[1]].CoSuspects.Add(table[chat[0]]); 
      } 
     } 

     Console.WriteLine("All members"); 
     foreach (var key in table) 
     { 
      Console.WriteLine("{0} talked to {1}", key.Key, string.Join(", ", key.Value.CoSuspects.Select(t => t.ID.ToString()))); 
     } 

     Console.WriteLine("\nSuspected members"); 
     foreach (var key in table.Where(t => suspects.Contains(t.Key))) 
     { 
      Console.WriteLine("{0} talked to {1}", key.Key, string.Join(", ", key.Value.CoSuspects.Select(t => t.ID.ToString()))); 
     } 
    } 

我的辅助方法和类:

class Suspect 
    { 
     public Suspect(int id) 
     { 
      CoSuspects = new HashSet<Suspect>(); 
      this.ID = id; 
     } 
     public int ID { get; set; } 
     public HashSet<Suspect> CoSuspects { get; set; } 
    } 

    int[][] GetRandomData() 
    { 
     var list = new List<int[]>(); 
     var random = new Random(); 

    for (int i = 0; i < 100; i++) 
     { 
      list.Add(new[] { random.Next(10), random.Next(10) }); 
     } 

     return list.ToArray(); 
    } 

    int[] GetSuspects() 
    { 
     var random = new Random(); 

     var list = new List<int>(); 

    for (int i = 0; i < 3; i++) 
     { 
      list.Add(random.Next(10)); 
     } 
     return list.ToArray(); 
    } 
+0

谢谢你的帮助。正如前面提到的,我很难选择一个解决方案,但是我选择了Jun's,因为他首先回答,并且在我的问题的限制之内。我知道如何在不使用LINQ/lambda表达式的情况下解决这个问题,但看到你的解决方案对我很有帮助(另一种攻击方式)。 – phan

相关问题