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