Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save cs3b/d4465e2e906ad1cb2f43 to your computer and use it in GitHub Desktop.
Save cs3b/d4465e2e906ad1cb2f43 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
using (StreamReader reader = File.OpenText(args[0]))
{
UsersAndGroupsRepository usersAndGroups = new UsersAndGroupsRepository();
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (null == line)
{
continue;
}
usersAndGroups.ParseSerializedUserFriendsGroups(line);
}
var users = usersAndGroups.GetAllUsers();
var groupRecommendationService = new GroupsRecommedationService();
var usersAndRecommendedGroups = new Dictionary<User, ICollection<Group>>();
foreach (var user in users)
{
var recommendedGroups = groupRecommendationService.GetRecommendedGroups(user, usersAndGroups);
usersAndRecommendedGroups[user] = recommendedGroups;
}
var resultSerializer = new UserWithRecommendedGroupsSerializer();
var result = resultSerializer.SerializeAll(usersAndRecommendedGroups);
Console.Out.Write(result);
}
}
class UsersFactory
{
private Dictionary<string, User> usersLookup;
public UsersFactory()
{
usersLookup = new Dictionary<string, User>();
}
public User CreateUser(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
if (!usersLookup.ContainsKey(name) || usersLookup[name] == null)
{
usersLookup[name] = new User(name);
}
return usersLookup[name];
}
public List<User> CreateUsers(IEnumerable<string> names)
{
List<User> users = new List<User>();
foreach (var name in names)
{
var user = CreateUser(name);
if (user != null)
{
users.Add(user);
}
}
return users;
}
public ICollection<User> GetAllUsers()
{
return usersLookup.Values;
}
}
class GroupsFactory
{
private Dictionary<string, Group> groupsLookup;
public GroupsFactory()
{
groupsLookup = new Dictionary<string, Group>();
}
public Group CreateGroup(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
if (!groupsLookup.ContainsKey(name) || groupsLookup[name] == null)
{
groupsLookup[name] = new Group(name);
}
return groupsLookup[name];
}
public List<Group> CreateGroups(IEnumerable<string> names)
{
var groups = new List<Group>();
foreach (var name in names)
{
var group = CreateGroup(name);
if (group != null)
{
groups.Add(group);
}
}
return groups;
}
public ICollection<Group> GetAllGroups()
{
return groupsLookup.Values;
}
}
class User
{
public string Name;
public List<User> Friends;
public List<Group> Groups;
public User(string name)
{
this.Name = name;
this.Friends = new List<User>();
this.Groups = new List<Group>();
}
public override string ToString()
{
return this.Name;
}
}
class Group
{
public string Name;
public List<User> Members;
public Group(string name)
{
this.Name = name;
this.Members = new List<User>();
}
public bool IsMember(User user)
{
return this.Members.Contains(user);
}
public override string ToString()
{
return this.Name;
}
}
class UsersAndGroupsRepository
{
private UsersFactory usersFactory;
private GroupsFactory groupsFactory;
public UsersAndGroupsRepository()
{
usersFactory = new UsersFactory();
groupsFactory = new GroupsFactory();
}
public User ParseSerializedUserFriendsGroups(string serializedUserFriendsGroup)
{
string[] splitData = serializedUserFriendsGroup.Split(':');
if (splitData == null || splitData.Length == 0)
{
return null;
}
var userName = splitData[0];
var hasFriends = splitData.Length >= 1 && splitData[1] != null;
var serializedFriendsNames = hasFriends ? splitData[1] : string.Empty;
var friendsNames = serializedFriendsNames.Split(',');
var hasGroups = splitData.Length >= 2 && splitData[2] != null;
var serializedGroupNames = hasGroups ? splitData[2] : string.Empty;
var groupNames = serializedGroupNames.Split(',');
var user = usersFactory.CreateUser(userName);
var friends = usersFactory.CreateUsers(friendsNames);
user.Friends.AddRange(friends);
var groups = groupsFactory.CreateGroups(groupNames);
user.Groups.AddRange(groups);
foreach (var group in groups)
{
group.Members.Add(user);
}
return user;
}
public ICollection<User> GetAllUsers()
{
return usersFactory.GetAllUsers();
}
public ICollection<Group> GetAllGroups()
{
return groupsFactory.GetAllGroups();
}
}
class GroupsRecommedationService
{
// recommend groups where >= 50% of user's friends participate
// assumption - don't recommend groups that user already attends
public ICollection<Group> GetRecommendedGroups(User user, UsersAndGroupsRepository usersAndGroupsRepository)
{
var recommendedGroups = new List<Group>();
if (user == null)
{
return recommendedGroups;
}
var halfFriendsCount = 0.5f * user.Friends.Count;
var requiredNumberOfFriends = (int)Math.Ceiling(halfFriendsCount);
var groups = usersAndGroupsRepository.GetAllGroups().ToList<Group>();
foreach (var group in user.Groups)
{
if (groups.Contains(group))
{
groups.Remove(group);
}
}
foreach (var group in groups)
{
if (IsRecommended(group, user.Friends, requiredNumberOfFriends))
{
recommendedGroups.Add(group);
}
}
return recommendedGroups;
}
private bool IsRecommended(Group group, IEnumerable<User> friends, int requiredNumberOfFriends)
{
var friendsInGroupCount = 0;
foreach (var friend in friends)
{
if (group.IsMember(friend))
{
friendsInGroupCount += 1;
}
}
return friendsInGroupCount >= requiredNumberOfFriends;
}
}
class UserWithRecommendedGroupsSerializer
{
public string SerializeAll(Dictionary<User, ICollection<Group>> usersAndRecommendedGroups)
{
StringBuilder stringBuilder = new StringBuilder();
var users = usersAndRecommendedGroups.Keys.OrderBy(u => u.Name);
foreach (var user in users)
{
var serializedLine = Serialize(user, usersAndRecommendedGroups[user]);
stringBuilder.Append(serializedLine);
}
return stringBuilder.ToString();
}
private string Serialize(User user, ICollection<Group> recommendedGroups)
{
if (user == null || recommendedGroups == null || recommendedGroups.Count == 0)
{
return string.Empty;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(user.Name);
stringBuilder.Append(":");
var isFirstGroup = true;
foreach (var group in recommendedGroups)
{
if (!isFirstGroup)
{
stringBuilder.Append(",");
}
else
{
isFirstGroup = false;
}
stringBuilder.Append(group.Name);
}
stringBuilder.Append("\n");
return stringBuilder.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment