Consider using set based operations to solve this with Linq.
Given the data structure you proposed, to solve the problem you need to solve for both direct friends and indirect friends. There are 2 cases for direct friends. 1, where the common friend is NameFriend1, the other is nameFriend2. These two cases are solved at the end of the method IndirectFriends.
For indirect friends, the case gets more complicated, because you will need to join the results of the direct friends to the same dataset twice, one for where the direct friend is NameFriend1 on the 2nd list, another for when it's NameFriend2. That is why there are 4 cases to resolve.
At the end of the method IndirectFriends, I exclude the common friend from the list and return only distinct results.
Please note, this code only works because the same object brian is being used in the list and also for comparisons. If you are instantiating new variables with the same values and you want them to be evaluated by linq as being equal, you'll need to implement the IComparable interface Link below
How to Implement IComparable interface?
[TestMethod]
public void TestMethod1()
{
List<BestFriends> ListOfBestFriends = new List<BestFriends>();
var adam = new Friend { Name = "Adam" };
var brian = new Friend { Name = "Brian" };
var chris = new Friend { Name = "Chris" };
var daniel = new Friend { Name = "Daniel" };
var eddie = new Friend { Name = "Eddie" };
var ian = new Friend { Name = "Ian" };
var john = new Friend { Name = "John" };
ListOfBestFriends.Add(new BestFriends { NameFriend1 = adam, NameFriend2 = brian });
ListOfBestFriends.Add(new BestFriends { NameFriend1 = brian, NameFriend2 = chris });
ListOfBestFriends.Add(new BestFriends { NameFriend1 = chris, NameFriend2 = daniel });
ListOfBestFriends.Add(new BestFriends { NameFriend1 = eddie, NameFriend2 = ian });
ListOfBestFriends.Add(new BestFriends { NameFriend1 = brian, NameFriend2 = john });
var result = IndirectFriends(brian, ListOfBestFriends);
}
List<Friend> IndirectFriends(Friend commonFriend, List<BestFriends> bestFriendsPairs)
{
/* Get inDirect Friends where commonfriend = NameFriend2 */
/* First list is joined on Namefriend2 and Namefriend1 */
var l1 = (from bfp in bestFriendsPairs
join bfpR in bestFriendsPairs
on bfp.NameFriend2 equals bfpR.NameFriend1
where bfp.NameFriend1 == commonFriend
select bfpR.NameFriend2).ToList();
/* Get inDirect Friends where commonfriend= NameFriend2 */
/* First list is joined on Namefriend2 and Namefriend2 */
l1.AddRange(from bfp in bestFriendsPairs
join bfpR in bestFriendsPairs
on bfp.NameFriend2 equals bfpR.NameFriend2
where bfp.NameFriend1 == commonFriend
select bfpR.NameFriend1);
/* Get InDirect Friends where commonfriend = NameFriend2 */
/* First list is joined on Namefriend1 and Namefriend2 */
l1.AddRange (from bfp in bestFriendsPairs
join bfpL in bestFriendsPairs
on bfp.NameFriend1 equals bfpL.NameFriend2
where bfp.NameFriend2 == commonFriend
select bfpL.NameFriend1);
/* Get InDirect Friends where commonfriend= NameFriend2 */
/* First list is joined on Namefriend1 and Namefriend1 */
l1.AddRange(from bfp in bestFriendsPairs
join bfpL in bestFriendsPairs
on bfp.NameFriend1 equals bfpL.NameFriend1
where bfp.NameFriend2 == commonFriend
select bfpL.NameFriend2);
/* Get Direct Friends where commonfriend= NameFriend2 */
l1.AddRange(from bfp in bestFriendsPairs
where bfp.NameFriend2 == commonFriend
select bfp.NameFriend1);
/* Get Direct Friends where commonfriend= NameFriend1 */
l1.AddRange(from bfp in bestFriendsPairs
where bfp.NameFriend1 == commonFriend
select bfp.NameFriend2);
/*exclude commonfriend, and get distinct */
return l1.Where(f=>f!= commonFriend).Distinct().ToList();
}