人们共享相同项目的次数C#

时间:2018-01-26 18:42:40

标签: c# list linq group-by

我有一群朋友,他们有0,1或者许多代币。 我试图找出朋友共享同一个令牌的次数。因此,如果friend1有令牌1,2和3,则friend2具有令牌1和2,而朋友3具有令牌1,2和3.它将返回该朋友2和friend1共享2个令牌而friend3 和朋友1分享3个令牌等 我有代码对令牌进行分组并获取与其关联的朋友数量。我只是不确定如何与朋友分享令牌。我想可能有一些方法可以用linq做到这一点,但不确定如何或是否有另一种更好的方法。

List<string>.

3 个答案:

答案 0 :(得分:0)

仅仅比较两个朋友,我们可以做一些简单的事情,例如:friend1.Tokens.Intersect(friend2.Tokens)

通过朋友列表,我们可能希望将相关数据收集到列表中。对于列表中的每个朋友,我们可以通过在Where子句中使用上面的代码来获得与他共享令牌的其他朋友。

我们还可以通过在朋友组的SelectMany媒体资源上使用Tokens来获取共享令牌列表。通过这两个列表,我们可以轻松地显示每个朋友和所有其他朋友之间的共享数据。

注意:我修改了类以覆盖ToString()方法,以简化将它们写入控制台的过程:

public class Token
{
    public int Id { get; set; }

    public override string ToString()
    {
        return $"token{Id}";
    }
}

public class Friend
{
    public int Id { get; set; }
    public List<Token> Tokens { get; set; }

    public override string ToString()
    {
        return $"friend{Id}";
    }
}

这是在一组朋友之间显示共享令牌信息的一个示例。下面的代码创建了一个包含三个朋友的列表,其中第一个和第三个拥有令牌1,2和3,第二个拥有令牌1和2(注意我在右侧标记了.ToList()Tokens赋值,以确保每个列表在内存中都有一个单独的位置):

private static void Main()
{
    var tokens = new List<Token>
    {
        new Token {Id = 1},
        new Token {Id = 2},
        new Token {Id = 3},
    };

    var friends = new List<Friend>
    {
        new Friend {Id = 1, Tokens = tokens.ToList()},
        new Friend {Id = 2, Tokens = tokens.Take(2).ToList()},
        new Friend {Id = 3, Tokens = tokens.ToList()},
    };

    // List out our friends and their shared tokens
    foreach (var friend in friends)
    {
        // Get the friends where the intersection of this friend's tokens 
        // and the other friend's tokens has one or more items
        var sharedFriends = friends.Where(f =>
            f.Id != friend.Id &&
            f.Tokens.Intersect(friend.Tokens).Any());

        if (sharedFriends.Any())
        {
            var sharedTokens = friend.Tokens.Intersect(
                sharedFriends.SelectMany(f => f.Tokens));

            Console.WriteLine($"\n{friend} shares {sharedTokens.Count()} tokens:");

            foreach (var sharedToken in sharedTokens)
            {
                var friendsSharingThisToken =
                    sharedFriends.Where(f => f.Tokens.Contains(sharedToken));

                Console.WriteLine(" - {0} shared with: {1}", sharedToken, 
                    string.Join(", ", friendsSharingThisToken));
            }
        }
        else
        {
            Console.WriteLine($"\n{friend} is not sharing tokens with anyone else.");
        }
    }

    Console.Write("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

<强>输出

enter image description here

答案 1 :(得分:0)

你提到过......

  

或者还有其他更好的方式。

这有帮助吗?

void Main()
{
    var t1 = new Token {TokenId = 1};
    var t2 = new Token {TokenId = 2};
    var t3 = new Token {TokenId = 3};

    var p1 = new Friend {FriendID = 1, oToken = new List<Token>{t1,t2,t3}};
    var p2 = new Friend {FriendID = 2, oToken = new List<Token>{t1,t2}};
    var p3 = new Friend {FriendID = 3, oToken = new List<Token>{t1,t2,t3}};

    var friends = new List<Friend>{p1,p2,p3};

    for (int i = 0; i < friends.Count; i++)
    {
        for (int j = i+1; j < friends.Count; j++)
        {
            Console.WriteLine("Friend {0} and Friend {1} share {2} tokens", friends[i].FriendID, friends[j].FriendID, friends[i].oToken.Intersect(friends[j].oToken).Count());
        }
    }
}

使用与您定义的相同的类。

答案 2 :(得分:0)

使用提供可能的朋友组合的扩展方法:

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k) {
    return k == 0 ? new[] { new T[0] } :
      elements.SelectMany((e, i) =>
        elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}

您可以计算每对朋友共享的令牌数量,并抛弃不共享令牌的对。 LINQ Intersect方法produces the set intersection of two sequences by using the default equality comparer to compare values然后我们计算这些常见元素。

var tokensFriendCount = distinctFriendList.Where(f => f.oToken != null)
                                          .Combinations(2) // get pairs of friends
                                          .Select(fp => fp.ToList()) // convert each sub-IEnumerable to List to make below simpler
                                          .Select(fp => new {
                                              Friend1 = fp[0],
                                              Friend2 = fp[1],
                                              SharedCount = fp[0].oToken.Intersect(fp[1].oToken).Count()
                                          })
                                          .Where(fpc => fpc.SharedCount > 0); // throw out pairs that share no tokens

上面的计数假设每个Token对象都是唯一的,特别是TokenId是唯一的,如果不是这样(虽然你先前的查询暗示它是),你可以根据{ {1}}:

TokenId

如果您只想要摘要,可以简化答案:

SharedCount = fp[0].oToken.Select(t => t.TokenId).Intersect(fp[1].oToken.Select(t => t.TokenId)).Count()

如果您不想使用扩展程序,可以直接生成这些组合:

var summarySharedTokenCount = tokensFriendCount.Select(tfc => new {
    Friend1Id = tfc.Friend1.FriendID,
    Friend2Id = tfc.Friend2.FriendID,
    tfc.SharedCount
}).ToList();