4

据我所知,LINQ 和 lambda 表达式是解决我的特定问题的方法。在我的办公室里,我有一个二维数组 [X 长度][2 宽度] 中的 IM 日志列表,这样我就可以看到谁 IM 了谁。但日志包含 3 位数的用户 ID,而不是实际名称。

arrIMLog[x][1]

所以,一个日志条目可能看起来像这样 arrIMLog[0][0] = 353 和 arrIMLog[0][1] = 563 意味着用户 353 IM'ed 用户 563。然后,我有一个用户 ID 列表,我为其想通过搜索日志找出他们与谁进行了即时通讯。

lstSuspects

例如,lstSuspects(1) = 353、lstSuspects(2) = 563 等。我想创建一个新的简单列表 lstSuspectsContacted,这样我就可以找出 lstSuspects 上每个人联系过的唯一 UserID(# of时间并不重要)。我该怎么做呢?

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] 元素,具体取决于 lstSuspects 与其他元素 [1] 或 [0] 中的 arrIMLog 之间是否匹配。我不知道如何实现这一点。

4

3 回答 3

1

One way of solving it by stepping out of the box, since I would never treat this as a LINQ-problem. What I'm doing is to remodel it as a network structure. And we are only traversing the log once, which really might become an issue if we are looking at a large dataset.

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

My helper methods and classes:

  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();
  }
于 2013-10-21T18:03:43.427 回答
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);
    }
于 2013-10-21T00:29:05.750 回答
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);
    }       

}

结果:

结果

于 2013-10-21T03:14:00.080 回答