How to solve manager peer problem question? [closed] - algorithm

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 months ago.
Improve this question
I was asked below question in google interview but could not answer it. I did google search but could not find any correct solution for this problem. Can you please help me to provide a solution for this problem?
Design a data structure to support following functions:
setManager(A, B) sets A as a direct manager of B
setPeer(A, B) sets A as a colleague of B. After that, A and B will have the same direct Manager.
query(A, B) returns if A is in the management chain of B.
Every person only has 1 direct manager.

Let's consider each group of peers as a node in the hierarchy tree that represents the company management chain. We know that it's a tree because each person only has 1 direct manager.
We'll have the tree of the following form:
Quick ideas:
setManager is just connecting 2 nodes (and also creating node if not already existed).
setPeer is just updating a node to include the other peer (if node already existed); or creating a node for both peers (if none of the node existed); or merging 2 existing nodes (if 2 nodes were created independently for each peer).
query(A, B) is just to traverse the tree upwards and check if a node on that path contains employee A.
One extra issue: given an employee X, we need to get the access to the corresponding node (can be solved by having an extra hash table, which map from every employee to the reference of their corresponding node).
The code for the above idea
public class EmployeeManagement {
private Dictionary < string, Node > _employeeToNode;
public EmployeeManagement() {
_employeeToNode = new Dictionary < string, Node > ();
}
public void SetManager(string manager, string employee) {
if (!_employeeToNode.ContainsKey(manager)) {
_employeeToNode[manager] = new Node(null, manager);
}
if (!_employeeToNode.ContainsKey(employee)) {
_employeeToNode[employee] = new Node(_employeeToNode[manager], employee);
} else {
_employeeToNode[employee].SetManagerNode(_employeeToNode[manager]);
}
}
public void SetPeer(string employeeA, string employeeB) {
if (_employeeToNode.ContainsKey(employeeA) && _employeeToNode.ContainsKey(employeeB)) {
if (_employeeToNode[employeeA].HasEmployee(employeeB) &&
_employeeToNode[employeeB].HasEmployee(employeeA)) {
return;
}
// Merge node of A and B if distinct
Node newNode = _employeeToNode[employeeA];
Node oldNode = _employeeToNode[employeeB];
if (_employeeToNode[employeeB].EmployeeCount() > newNode.EmployeeCount()) {
newNode = _employeeToNode[employeeB];
oldNode = _employeeToNode[employeeA];
}
if (!newNode.HasManager()) {
newNode.SetManagerNode(oldNode.GetManagerNode());
}
foreach(var employee in oldNode.GetEmployees()) {
newNode.AddEmployee(employee);
}
_employeeToNode[employeeA] = newNode;
_employeeToNode[employeeB] = newNode;
foreach(var employee in oldNode.GetEmployees()) {
_employeeToNode[employee] = newNode;
}
} else if (_employeeToNode.ContainsKey(employeeA)) {
_employeeToNode[employeeB] = _employeeToNode[employeeA];
} else if (_employeeToNode.ContainsKey(employeeB)) {
_employeeToNode[employeeA] = _employeeToNode[employeeB];
} else {
// Create a new node for both A and B
Node forAB = new Node(null, employeeA);
forAB.AddEmployee(employeeB);
_employeeToNode[employeeA] = forAB;
_employeeToNode[employeeB] = forAB;
}
}
/// <summary>
/// Check if A is in the management chain of B
/// </summary>
public bool Query(string employeeA, string employeeB) {
if (!_employeeToNode.ContainsKey(employeeA) || !_employeeToNode.ContainsKey(employeeB)) {
return false; // no info of employee A or employee B yet
}
Node managersOfB = _employeeToNode[employeeB].GetManagerNode();
while (managersOfB != null) {
if (managersOfB.HasEmployee(employeeA)) {
return true;
}
managersOfB = managersOfB.GetManagerNode();
}
return false; // not found A in the management chain of B
}
}
private class Node {
private Node _directManagers;
private HashSet < string > _employees;
public Node(Node directManagers, string employee) {
_directManagers = directManagers;
_employees = new HashSet < string > ();
_employees.Add(employee);
}
public bool HasManager() {
return _directManagers != null;
}
public void SetManagerNode(Node directManagers) {
_directManagers = directManagers;
}
public Node GetManagerNode() {
return _directManagers;
}
public void AddEmployee(string employee) {
_employees.Add(employee);
}
public HashSet < string > GetEmployees() {
return _employees;
}
public bool HasEmployee(string employee) {
return _employees.Contains(employee);
}
public int EmployeeCount() {
return _employees.Count;
}
}

This can be done with a single class, Employee, which contains an attribute/member _manager, which is a reference to this employees manager if any and an attribute/member '_managees', a set of all Employee instances/objects that this employee manages.
Note: I am going exclusively by my interpretation of the problem definition, which were bullet points 1-3 and not by the OP's or any other person's interpretation. The description for setPeer is sets A as a colleague of B. After that, A and B will have the same direct Manager. Thus when you call setPeer(A, B), you are setting A's manager to be B's manager and that it doesn't make any sense unless B has a manager. And everyone has a manager except for the head boss, and by definition the head boss can have no peers. So perhaps A just got a promotion (or a demotion or just a lateral move to another department). It doesn't mean that every former peer of A has gotten the same promotion and now have the same new manager, too. So I see this a less-complicated problem than others are making of it.
class Employee:
def __init__(self, name, manager=None):
self._name = name
self._managees = set()
self._manager = None # so far
if manager:
self.set_manager(manager) # Could be none if this is the "top dog"
def __repr__(self):
return f'Name: {self._name}, Managed By: {self._manager._name if self._manager else ""}, Manages: {[managee._name for managee in self._managees]}'
def get_name(self):
return self._name
def get_manager(self):
return self._manager
def get_managees(self):
return self._managees
def manages(self, employee):
return employee in self._managees
def is_managed_by(self, employee):
return self._manager is employee
def remove_manager(self):
"""
We are no longer managed by anyone.
"""
if self._manager:
self._manager.remove_managee(self)
self._manager = None
return self
def remove_managee(self, managee):
"""
This manager no longer manages managee.
"""
self._managees.remove(managee)
managee._manager = None # No longer has a manager
return self
def set_manager(self, manager):
if not manager:
self.remove_manager()
return self
if self._manager:
# We have an existing manager:
self._manager.remove_managee(self)
self._manager = manager
manager._managees.add(self)
return self
def add_managee(self, managee):
"""
This manager now manages managee.
"""
managee.set_manager(self)
return sell
def set_peer(self, managee):
assert managee._manager # Make sure managee can have a peer
self.set_manager(managee._manager)
return self
#staticmethod
def query(employee1, employee2):
"""
Is employee1 in the management chain of employee2?
"""
manager = employee2._manager
while manager:
if manager is employee1:
return True
manager = manager._manager
return False
tom = Employee('Tom')
dick = Employee('Dick', tom)
harry = Employee('Harry', dick)
sally = Employee('Sally')
sally.set_manager(harry)
assert sally.is_managed_by(harry) and harry.manages(sally)
sally.set_manager(tom)
assert sally.is_managed_by(tom) and tom.manages(sally)
sally.set_peer(harry)
assert sally.is_managed_by(dick) and dick.manages(sally)
assert Employee.query(tom, harry)
assert not Employee.query(harry, dick)
print(tom)
print(dick)
print(harry)
print(sally)
Prints:
Name: Tom, Managed By: , Manages: ['Dick']
Name: Dick, Managed By: Tom, Manages: ['Harry', 'Sally']
Name: Harry, Managed By: Dick, Manages: []
Name: Sally, Managed By: Dick, Manages: []

Use three hash tables 1. employee to group id mapping (emp) 2. group id to list of employees (gid) 3. group id -> manager id table (manager)
int id = 0;
void setpeer(string A, string B) {
int id1 = 0;
int id2 = 0;
if (emp.find(A) != emp.end())
id1 = emp[A];
if (emp.find(B) != emp.end())
id2 = emp[B];
if (!id1 && !id2) {
++id;
emp[A] = id;
emp[B} = id;
gid[id].push_back(A);
gid[id].push_back(B);
} else if (!id1) {
emp[A] = id2;
gid[id2].push_back(A);
} else if (!id2) {
emp[B] = id1;
gid[id1].push_back(B);
} else {
for(i = 0;i<gid[id2].size();i++) {
emp[gid[id2][i]] = id1;
gid[id1].push_back( gid[id2][i] );
}
if (manager.find(id2) != manager.end())
manager[id1] = manager[id2].
manager.erase(id2);
gid.erase(id2);
}
void setManager(string A, string B) {
int id1, id2;
if (emp.find(A) != emp.end())
id1 = emp[A];
else {
++id;
emp[A] = id;
id1 = id;
gid[id].push_back(A);
}
if (emp.find(B) != emp.end())
id2 = emp[B];
else {
++id;
emp[B] = id;
id2 = id;
gid[id].push_back(B);
}
manager[id2] = id1;
}
bool query(string A, string B) {
int id1 = 0, id2 = 0;
if (emp.find(A) != emp.end())
id1 = emp[A];
if (emp.find(B) != emp.end())
id2 = emp[B];
if (!id1 || !id2) //one of them does not exist
return false;
id2 = manager[id2];
while(id2 != 0) {
if (id2 == id1)
return true;
id2 = manager[id2];
}
return false;
}

Say you have the following person class:
struct Person {
// we need to store the manager, obviously
Person* manager = nullptr;
// we also need to store the peers to assign the correct
// manager for all when it is set for one person in the group
shared_ptr<vector<Person*>> peerGroup = make_shared<vector<Person*>>({this});
};
A person, when newly created, has no manager and a peer group containing only the person itself.
Assuming A, B, etc. are not strings but Person*, you can implement the methods as follows:
void setManager(Person* a, Person* b) {
for (Person* person : *b->peerGroup) person->manager = a;
}
void setPeer(Person* a, Person* b) {
// merge peer groups of a and b
// by first adding b's peers to a's peer group
// and then setting b's peer group to a's peer group
for (Person* person : *b->peerGroup) a->peerGroup->push_back(person);
b->peerGroup = a->peerGroup;
}
bool query(Person* a, Person* b) {
// we want to find out if a is managed by b
// so we go up the hierarchy, starting from a
Person* current = a;
while (current->manager != nullptr) {
// stop if b is (indirect) manager of a
if (current->manager == b) return true;
current = current->manager;
}
// we reached the top of the hierarchy and did not find b
return false;
}
In case you actually receive strings (like "A", "B", ...) you could just use a hashmap to see if you already created a Person object for this name and if not create one:
map<string, unique_ptr<Person>> persons;
Person* getPerson(string name) {
if (!persons.contains(name)) {
persons[name] = make_unique<Person>();
}
return persons[name].get()
}

Related

Replacing for loops for searching list in kotlin

I am trying to convert my code as clean as possible using the Kotlin's built-in functions. I have done some part of the code using for loops. But I want to know the efficient built-in functions to be used for this application
I have two array lists accounts and cards.
My goal is to search a specific card with the help of its card-number, in the array list named cards.
Then I have to validate the pin. If the pin is correct, by getting that gift card's customerId I have to search the account in the array list named accounts. Then I have to update the balance of the account.
These are the class which I have used
class Account{
constructor( )
var id : String = generateAccountNumber()
var name: String? = null
set(name) = if (name != null) field = name.toUpperCase() else { field = "Unknown User"; println("invalid details\nAccount is not Created");}
var balance : Double = 0.0
set(balance) = if (balance >= 0) field = balance else { field = 0.0 }
constructor(id: String = generateAccountNumber(), name: String?,balance: Double) {
this.id = id
this.balance = balance
this.name = name
}
}
class GiftCard {
constructor( )
var cardNumber : String = generateCardNumber()
var pin: String? = null
set(pin) = if (pin != null) field = pin else { field = "Unknown User"; println("Please set the pin\nCard is not Created");}
var customerId : String = ""
set(customerId) = if (customerId != "") field = customerId else { field = "" }
var cardBalance : Double = 0.0
set(cardBalance) = if (cardBalance > 0) field = cardBalance else { field = 0.0; println("Card is created with zero balance\nPlease deposit") }
var status = Status.ACTIVE
constructor(cardNumber: String = generateCardNumber(),
pin: String,
customerId: String,
cardBalance: Double = 0.0,
status: Status = Status.ACTIVE){
this.cardNumber = cardNumber
this.pin = pin
this.customerId = customerId
this.cardBalance = cardBalance
this.status = status
}
}
This is the part of code, I have to be changed :
override fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
for (giftcard in giftcards) {
if (giftcard.cardNumber == cardNumber) {
if (giftcard.pin == pin) {
giftcard.status = Status.CLOSED
for (account in accounts)
account.balance = account.balance + giftcard.cardBalance
giftcard.cardBalance = 0.0
return Pair(true,true)
}
\\invalid pin
return Pair(true,false)
}
}
\\card is not present
return Pair(false,false)
}
Both classes are not very idiomatic. The primary constructor of a Kotlin class is implicit and does not need to be defined, however, you explicitly define a constructor and thus you add another one that is empty.
// good
class C
// bad
class C {
constructor()
}
Going further, Kotlin has named arguments and default values, so make use of them.
class Account(
val id: String = generateAccountNumber(),
val name: String = "Unknown User",
val balance: Double = 0.0
)
Double is a very bad choice for basically anything due to its shortcomings, see for instance https://www.floating-point-gui.de/ Choosing Int, Long, heck even BigDecimal would be better. It also seems that you don’t want the balance to ever go beneath zero, in that case consider UInt and ULong.
Last but not least is the mutability of your class. This can make sense but it also might be dangerous. It is up to you to decide upon your needs and requirements.
enum class Status {
CLOSED
}
#ExperimentalUnsignedTypes
class Account(private var _balance: UInt) {
val balance get() = _balance
operator fun plusAssign(other: UInt) {
_balance += other
}
}
#ExperimentalUnsignedTypes
class GiftCard(
val number: String,
val pin: String,
private var _status: Status,
private var _balance: UInt
) {
val status get() = _status
val balance get() = _balance
fun close() {
_status = Status.CLOSED
_balance = 0u
}
}
#ExperimentalUnsignedTypes
class Main(val accounts: List<Account>, val giftCards: List<GiftCard>) {
fun closeCard(cardNumber: String, pin: String) =
giftCards.find { it.number == cardNumber }?.let {
(it.pin == pin).andAlso {
accounts.forEach { a -> a += it.balance }
it.close()
}
}
}
inline fun Boolean.andAlso(action: () -> Unit): Boolean {
if (this) action()
return this
}
We change the return type from Pair<Boolean, Boolean> to a more idiomatic Boolean? where Null means that we did not find anything (literally the true meaning of Null), false that the PIN did not match, and true that the gift card was closed. We are not creating a pair anymore and thus avoid the additional object allocation.
The Boolean.andAlso() is a handy extension function that I generally keep handy, it is like Any.also() from Kotlin’s STD but only executes the action if the Boolean is actually true.
There's probably a million different ways to do this, but here's one that at least has some language features I feel are worthy to share:
fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
val giftCard = giftcards.find { it.cardNumber == cardNumber }
?: return Pair(false, false)
return if (giftCard.pin == pin) {
giftCard.status = Status.CLOSED
accounts.forEach {
it.balance += giftCard.cardBalance
}
Pair(true, true)
} else
Pair(true, false)
}
The first thing to notice if the Elvis operator - ?: - which evaluates the right side of the expression if the left side is null. In this case, if find returns null, which is equivalent to not finding a card number that matches the desired one, we'll immediately return Pair(false, false). This is the last step in your code.
From there one it's pretty straight forward. If the pins match, you loop through the accounts list with a forEach and close the card. If the pins don't match, then we'll go straight to the else branch. In kotlin, if can be used as an expression, therefore we can simply put the return statement before the if and let it return the result of the last expression on each branch.
PS: I won't say this is more efficient than your way. It's just one way that uses built-in functions - find and forEach - like you asked, as well as other language features.
PPS: I would highly recommend to try and find another way to update the lists without mutating the objects. I don't know your use cases, but this doesn't feel too thread-safe. I didn't post any solution for this, because it's outside the scope of this question.

Optimizations for a recursive formula finding a path between two random nodes

I have written a recursive formula that finds a path between two nodes arranged in a grid pattern. My code works with two problems. The first is that sometimes the start node's position is changed from one to another number, but I fixed this by reassigning it after the recursion so it's not that big of a deal. The second issue is that it runs unbearably slow. It takes about 30 seconds to generate a 5x5 and I haven't been able to generate a 7x7 which is my ultimate goal. I am hoping that someone will see if there are any optimizations that can be made.
The Node class, shown below, has a Key property and a Value property. The Key is the position in the grid starting at 0. So, for a 5x5, the top left node will have a Key of 0 and the bottom right node will have a Key of 24. Each node has Up, Down, Left and Right properties that are the other nodes it is connected to. When there are no nodes in that direction, the value is null. For example, in a 5x5, a node with Key = 0 will have an Up of null, a Down of the node with Key = 5, a Left of null, and a Right of the node with Key = 1. As another example, still in a 5x5, a node with Key = 6 will have an Up of the node with Key = 1, a Down of the node with Key = 11, a Left of the node with Key = 5, and a Right of the node with Key = 7. The Position property is the path. The path starts with the node with Position = 1, then goes to the node with Position = 2 etc. until it reaches the end node, which would be position N*N on a NxN board (e.g. a 5x5 board would have an end node with position 25). These nodes are added to a list called nodeList-(a global variable). One of these nodes gets randomly marked as Start-(boolean) and a different node gets randomly assigned as End-(boolean).
The next part is the path. We want to find a random path (starting at 1) between the Start and End nodes that touches every other node without touching the same node twice. This is for a game, so it is important that it is random so the user doesn't play the same board twice. If this is not possible given the Start and End Positions, new Start and End positions are chosen and the algorithm is run again.
class Node
{
public int Key { get; set; }
public int? Position { get; set; } = null;
public Node Up { get; set; } = null;
public Node Down { get; set; } = null;
public Node Left { get; set; } = null;
public Node Right { get; set; } = null;
public bool Start = false;
public bool End = false;
public Node(int key)
{
Key = key;
}
}
public bool GeneratePath()
{
var current = nodeList.Where(w => w.Start).FirstOrDefault();
var start = current;
int position = 1;
bool Recurse(Node caller)
{
if (current.Position == null)
{
current.Position = position;
}
if (current.End)
{
return true;
}
var directions = GetDirections();
for (var i = 0; i < 4; i++)
{
var done = false;
if (directions[i] == 0 && current.Up != null && current.Up.Position == null
&& (!current.Up.End || position == n * n - 1))
{
var temp = current;
current = current.Up;
position++;
done = Recurse(temp);
}
else if (directions[i] == 1 && current.Down != null && current.Down.Position == null
&& (!current.Down.End || position == n * n - 1))
{
var temp = current;
current = current.Down;
position++;
done = Recurse(temp);
}
else if (directions[i] == 2 && current.Left != null && current.Left.Position == null
&& (!current.Left.End || position == n * n - 1))
{
var temp = current;
current = current.Left;
position++;
done = Recurse(temp);
}
else if (directions[i] == 3 && current.Right != null && current.Right.Position == null
&& (!current.Right.End || position == n*n - 1))
{
var temp = current;
current = current.Right;
position++;
done = Recurse(temp);
}
if(done)
{
return true;
}
}
current.Position = null;
position--;
if(caller == null)
{
return false;
}
current = caller;
return false;
}
var success = Recurse(null);
if (success)
{
start.Position = 1;
}
return success;
}
private int[] GetDirections()
{
List<int> toPerm = new List<int>();
for (var i = 0; i < 4; i++)
{
toPerm.Add(i);
}
Random random = new Random();
var perms = HelperMethods.GetPermutations(toPerm, toPerm.Count);
var randomNumber = random.Next(0, perms.Count());
var directions = perms.ElementAt(randomNumber).ToArray();
return directions;
}
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(o => !t.Contains(o)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
To reiterate, I am wondering if there are optimizations I can make as it runs too slow for my purposes.
So I found an implementation of an amazing algorithm that can produce 10,000 7x7's in 12 seconds. You can find the implementation here. The author is Nathan Clisby and it is based off of a paper “Secondary structures in long compact polymers”. The idea is to produce a non-random path between the two points, then randomly mutate the path as many times as the user wishes. Supposedly, with enough iterations, this algorithm can produce paths that are nearly as random as the algorithm I posted in the question.
Way to go computer scientists!

Linq join two lists: is it more efficient to use Dictionary?

Final rephrase
Below I join two sequences and I wondered if it would be faster to create a Dictionary of one sequence with the keySelector of the join as key and iterate through the other collection and find the key in the dictionary.
This only works if the key selector is unique. A real join has no problem with two records having the same key. In a dictionary you'll have to have unique keys
I measured the difference, and I noticed that the dictionary method is about 13% faster. In most use cases ignorable. See my answer to this question
Rephrased question
Some suggested that this question is the same question as LINQ - Using where or join - Performance difference?, but this one is not about using where or join, but about using a Dictionary to perform the join.
My question is: if I want to join two sequences based on a key selector, which method would be faster?
Put all items of one sequence in a Dictionary and enumerate the other sequence to see if the item is in the Dictionary. This would mean to iterate through both sequences once and calculate hash codes on the keySelector for every item in both sequences once.
The other method: use System.Enumerable.Join.
The question is: Would Enumerable.Join for each element in the first list iterate through the elements in the second list to find a match according to the key selector, having to compare N * N elements (is this called second order?) or would it use a more advanced method?
Original question with examples
I have two classes, both with a property Reference. I have two sequences of these classes and I want to join them based on equal Reference.
Class ClassA
{
public string Reference {get;}
...
}
public ClassB
{
public string Reference {get;}
...
}
var listA = new List<ClassA>()
{
new ClassA() {Reference = 1, ...},
new ClassA() {Reference = 2, ...},
new ClassA() {Reference = 3, ...},
new ClassA() {Reference = 4, ...},
}
var listB = new List<ClassB>()
{
new ClassB() {Reference = 1, ...},
new ClassB() {Reference = 3, ...},
new ClassB() {Reference = 5, ...},
new ClassB() {Reference = 7, ...},
}
After the join I want combinations of ClassA objects and ClassB objects that have an equal Reference. This is quite simple to do:
var myJoin = listA.Join(listB, // join listA and listB
a => a.Reference, // from listA take Reference
b => b.Reference, // from listB take Reference
(objectA, objectB) => // if references equal
new {A = objectA, B = objectB}); // return combination
I'm not sure how this works, but I can imagine that for each a in listA the listB is iterated to see if there is a b in listB with the same reference as A.
Question: if I know that the references are Distinct wouldn't it be more efficient to convert B into a Dictionary and compare the Reference for each element in listA:
var dictB = listB.ToDictionary<string, ClassB>()
var myJoin = listA
.Where(a => dictB.ContainsKey(a.Reference))
.Select(a => new (A = a, B = dictB[a.Reference]);
This way, every element of listB has to be accessed once to put in the dictionary and every element of listA has to be accessed once, and the hascode of Reference has to be calculated once.
Would this method be faster for large collections?
I created a test program for this and measured the time it took.
Suppose I have a class of Person, each person has a name and a Father property which is of type Person. If the Father is not know, the Father property is null
I have a sequence of Bastards (no father) that have exactly one Son and One Daughter. All Daughters are put in one sequence. All sons are put in another sequences.
The query: join the sons and the daughters that have the same father.
Results: Joining 1 million families using Enumerable.Join took 1.169 sec. Joining them using Dictionary join used 1.024 sec. Ever so slightly faster.
The code:
class Person : IEquatable<Person>
{
public string Name { get; set; }
public Person Father { get; set; }
// + a lot of equality functions get hash code etc
// for those interested: see the bottom
}
const int nrOfBastards = 1000000; // one million
var bastards = Enumerable.Range (0, nrOfBastards)
.Select(i => new Person()
{ Name = 'B' + i.ToString(), Father = null })
.ToList();
var sons = bastards.Select(father => new Person()
{Name = "Son of " + father.Name, Father = father})
.ToList();
var daughters = bastards.Select(father => new Person()
{Name = "Daughter of " + father.Name, Father = father})
.ToList();
// join on same parent: Traditionally and using Dictionary
var stopwatch = Stopwatch.StartNew();
this.TraditionalJoin(sons, daughters);
var time = stopwatch.Elapsed;
Console.WriteLine("Traditional join of {0} sons and daughters took {1:F3} sec", nrOfBastards, time.TotalSeconds);
stopwatch.Restart();
this.DictionaryJoin(sons, daughters);
time = stopwatch.Elapsed;
Console.WriteLine("Dictionary join of {0} sons and daughters took {1:F3} sec", nrOfBastards, time.TotalSeconds);
}
private void TraditionalJoin(IEnumerable<Person> boys, IEnumerable<Person> girls)
{ // join on same parent
var family = boys
.Join(girls,
boy => boy.Father,
girl => girl.Father,
(boy, girl) => new { Son = boy.Name, Daughter = girl.Name })
.ToList();
}
private void DictionaryJoin(IEnumerable<Person> sons, IEnumerable<Person> daughters)
{
var sonsDictionary = sons.ToDictionary(son => son.Father);
var family = daughters
.Where(daughter => sonsDictionary.ContainsKey(daughter.Father))
.Select(daughter => new { Son = sonsDictionary[daughter.Father], Daughter = daughter })
.ToList();
}
For those interested in the equality of Persons, needed for a proper dictionary:
class Person : IEquatable<Person>
{
public string Name { get; set; }
public Person Father { get; set; }
public bool Equals(Person other)
{
if (other == null)
return false;
else if (Object.ReferenceEquals(this, other))
return true;
else if (this.GetType() != other.GetType())
return false;
else
return String.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public override int GetHashCode()
{
const int prime1 = 899811277;
const int prime2 = 472883293;
int hash = prime1;
unchecked
{
hash = hash * prime2 + this.Name.GetHashCode();
if (this.Father != null)
{
hash = hash * prime2 + this.Father.GetHashCode();
}
}
return hash;
}
public override string ToString()
{
return this.Name;
}
public static bool operator==(Person x, Person y)
{
if (Object.ReferenceEquals(x, null))
return Object.ReferenceEquals(y, null);
else
return x.Equals(y);
}
public static bool operator!=(Person x, Person y)
{
return !(x==y);
}
}

LINQ and removing duplicates from an array of objects

I'm trying to de-dupe an array of objects using two columns where the second column is a Dictionary. Best way to describe this is to show some code:
class MyClass
{
public int ID;
public Dictionary<int, int> Dict = new Dictionary<int, int>();
}
And now to create some objects:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
What I'm looking to accomplish is to distinct by ID and Dict. The results should look like this:
List of MyClass objects (not pretty)
1 //MyClass.ID
1,1 //MyClass.Dictionary
1
1,2
2
1,1
Notice that one of the objects was dropped from the original list because it had a duplicate ID and Dict (dictionary values). I've been playing around with alternate versions of:
var s = from p in list
group p by p.ID into group1
from group2 in
(from p in group1 group p by p.Dict)
group group2 by group1.Key;
but just haven't had any luck. Appreciate any insight folks might have on solving this problem.
PS - I'm not changing the rules but I believe a GROUP BY and a SELECTFIRST will be cleaner than a DISTINCT with its extra code for a Comparer. A pat on the back for anyone who can figure this out using GROUP BY.
For reference types you should add equality comparer in order to do what you want. Add the following class:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass left, MyClass right)
{
if (left == null && right == null)
{
return true;
}
if (left == null || right == null)
{
return false;
}
if (left.ID == right.ID)
{
if (left.Dict == null && right.Dict == null)
{
return true;
}
if (left.Dict == null || right.Dict == null)
{
return false;
}
if (left.Dict.Count != right.Dict.Count)
{
return false;
}
foreach(var key in left.Dict.Keys)
{
if(!right.Dict.ContainsKey(key))
return false;
if (left.Dict[key] != right.Dict[key])
return false;
}
return true;
}
else return false;
}
public int GetHashCode(MyClass author)
{
return (author.ID).GetHashCode();
}
}
And use that comparer in Distinct override:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
var result = list.Distinct(new MyClassComparer()).ToList();
You should improve GetHashCode method. It will be your homework :)
Can I have half a pat for the following ? :)
var filteredList = list.GroupBy(mc => mc.ID)
.SelectMany(gr => gr.Distinct(new MyClassComparer()))
.ToList();
Comparer:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass a, MyClass b)
{
return a.Dict.Count == b.Dict.Count && !a.Dict.Except(b.Dict).Any();
}
public int GetHashCode(MyClass a)
{
return a.ID;
}
}

Algorith that determinates frequency of string combinations MQL4

I have csv file like this:
1392249600;EUR;CHF;USD;JPY;GBP
1392163200;GBP;JPY;USD;CHF;EUR
1392076800;GBP;CHF;EUR;JPY;USD
1391990400;JPY;USD;EUR;CHF;GBP
1391904000;GBP;EUR;CHF;USD;JPY
1391731200;GBP;EUR;CHF;JPY;USD
1391644800;EUR;CHF;USD;JPY;GBP
1391558400;JPY;USD;EUR;CHF;GBP
There can be over 15 000 rows in that file. I am trying to write code that could do such thing:
1.Takes first row saves it as parent. Then takes next 3 days as that childs.
2.Counts how often and which combination off childs with that parent are inside this file.
3.It creates something like summary for that so I could read todays combination and script shows the only the most frequent child combinations for next 3 days.
I don't have mathematical thinking so I have big problems to find solution myself.
What I think first I need script that generates all posible combinations of these colums made of EUR,CHF,USD,JPY,GBP so there is posible 5*4*3*2*1 = 120 combinations. Because they cant repeat in single row.
It will be like this.
First parent will be combination from first row like this: EUR;CHF;USD;JPY;GBP
Then 3 childs would be
GBP;JPY;USD;CHF;EUR
GBP;CHF;EUR;JPY;USD
JPY;USD;EUR;CHF;GBP
It saves this combination off parent and child elements.
Then again it starts from begining of the file, but moves one row below(like iteration +1).
then next all childs would be
GBP;CHF;EUR;JPY;USD
JPY;USD;EUR;CHF;GBP
GBP;EUR;CHF;USD;JPY
And again it saves these combinations for counting and make some frequency results.
And this cycle repeats for all rows on csv file.
Is there maybe some tips I should consider how to create this type of programm ?
Any tip would be great !
Thank You Very Much!
BB
Can you please clarify whether first value in a row in your file is date/time? 1392249600;EUR;CHF;USD;JPY;GBP
If yes, are you expecting that there will total 4 rows with the same date/time?
Or else you just need to go sequentially and use Line-1 as parent and then Line-2, Line-3, Line-4 as child and goes on... so that Line-5 becomes parent again?
To check whether country code is equivalent or not, you can use below kind of code. I am not 100% sure about your requirement, please correct me if you think this is not what you are looking for and I will try to answer you in other way:
package com.collections;
public class CountryCodeComparison {
public static void main(String[] args) {
//Read every row and sequentially insert value in CountryCode object.
//For ex. your row is: 1392163200;GBP;JPY;USD;CHF;EUR
String s1 = "1392163200;GBP;JPY;USD;CHF;EUR";
String [] array1 = s1.split(";");
CountryCode cc1 = new CountryCode(array1[1], array1[2], array1[1], array1[4], array1[5]);
//For ex. your row is: 1392076800;GBP;CHF;EUR;JPY;USD
String s2 = "1392076800;GBP;CHF;EUR;JPY;USD";
String [] array2 = s2.split(";");
CountryCode cc2 = new CountryCode(array2[1], array2[2], array2[1], array2[4], array2[5]);
if(cc1.equals(cc2)) {
System.out.println("Both CountryCode objects are equal.");
} else {
System.out.println("Both CountryCode objects are NOT equal.");
}
}
}
class CountryCode {
private String countryCode1;
private String countryCode2;
private String countryCode3;
private String countryCode4;
private String countryCode5;
public CountryCode(String countryCode1, String countryCode2,
String countryCode3, String countryCode4, String countryCode5) {
this.countryCode1 = countryCode1;
this.countryCode2 = countryCode2;
this.countryCode3 = countryCode3;
this.countryCode4 = countryCode4;
this.countryCode5 = countryCode5;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((countryCode1 == null) ? 0 : countryCode1.hashCode());
result = prime * result
+ ((countryCode2 == null) ? 0 : countryCode2.hashCode());
result = prime * result
+ ((countryCode3 == null) ? 0 : countryCode3.hashCode());
result = prime * result
+ ((countryCode4 == null) ? 0 : countryCode4.hashCode());
result = prime * result
+ ((countryCode5 == null) ? 0 : countryCode5.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CountryCode other = (CountryCode) obj;
if (countryCode1 == null) {
if (other.countryCode1 != null)
return false;
} else if (!countryCode1.equals(other.countryCode1))
return false;
if (countryCode2 == null) {
if (other.countryCode2 != null)
return false;
} else if (!countryCode2.equals(other.countryCode2))
return false;
if (countryCode3 == null) {
if (other.countryCode3 != null)
return false;
} else if (!countryCode3.equals(other.countryCode3))
return false;
if (countryCode4 == null) {
if (other.countryCode4 != null)
return false;
} else if (!countryCode4.equals(other.countryCode4))
return false;
if (countryCode5 == null) {
if (other.countryCode5 != null)
return false;
} else if (!countryCode5.equals(other.countryCode5))
return false;
return true;
}
}

Resources